我继承了一段(大的)代码,它有一个错误跟踪机制,其中将布尔变量传递给它们调用的所有方法,在执行的不同阶段,该方法被停止并返回,有时是一个默认值。
类似于(以前)的事情:
#include <iostream.h>
int fun1(int par1, bool& psuccess)
{
if(par1 == 42) return 43;
psuccess = false;
return -1;
}
int funtoo(int a, bool& psuccess)
{
int t = fun1(a, psuccess);
if(!psuccess)
{
return -1;
}
return 42;
}
void funthree(int b, bool& psuccess)
{
int h = funtoo(b, psuccess);
if(!psuccess)
{
return;
}
cout << "Yuppi" << b;
}
int main()
{
bool success = true;
funthree(43, success);
if(!success)
{
cout<< "Life, universe and everything have no meaning";
}
}请注意,这是C和C++代码的混合物,这正是项目的方式。
现在,出现了一个C魔术:“某人”定义了一个宏:
#define SUCCES_OR_RETURN if(!psuccess) return上面的程序变成(后):
#include<iostream.h>
int fun1(int par1, bool& psuccess)
{
if(par1 == 42) return 43;
psuccess = false;
return -1;
}
int funtoo(int a, bool& psuccess)
{
int t = fun1(a, psuccess);
SUCCES_OR_RETURN -1;
return 42;
}
void funthree(int b, bool& psuccess)
{
int h = funtoo(b, psuccess);
SUCCES_OR_RETURN ;
std::cout << "Yuppi" << b;
}
int main()
{
bool success = true;
funthree(43, success);
if(!success)
{
cout<< "Life, universe and everything have no meaning";
}
}问题是:我想知道是否有一种更好的方法来处理这种错误跟踪,或者我必须接受这一点。我个人不喜欢滥用C宏SUCCES_OR_RETURN ie。一旦用参数调用它,在其他情况下调用它时,它就像一个真正的return语句,但是我没有找到更好的解决方案来解决这个古老的设计。
请注意,由于平台的限制,我们有几个限制,但无论如何,我愿意听取关于这两个方面的意见:
throw (语法上接受,但不做任何操作,只是警告)。这个解决方案是在C++环境中解决这个问题的标准方法。编辑
此外,正如@BlueMoon在推荐中所建议的,创建一个全局变量是行不通的,因为在调用success变量的函数链的一开始,调用该变量的是类的一个成员变量,并且创建了该类的几个对象,每个对象都需要报告其成功状态:)
发布于 2014-05-05 11:27:07
在这里,混合C和C++错误处理策略出现了很大的故障:
引用链接文章,您的选项基本上可以归结为:
GetLastError()或OpenGL的glGetError()之类的函数来检索最近出现的错误代码。strerror函数。glfwSetErrorCallback。似乎您继承的代码的作者选择了一种非常奇怪的方式,传递一个指向布尔值的指针以供函数使用似乎很不寻常。
这篇文章有一些很好的例子,我个人喜欢这种风格:
libfoo_widget_container_t container = NULL;
libfoo_error_details_t error = NULL;
if (libfoo_create_widgets(12, &container, &error) != libfoo_success) {
printf("Error creating widgets: %s\n", libfoo_error_details_c_str(error));
libfoo_error_details_free(error);
abort(); // goodbye, cruel world!
}在这里,您得到了所有的东西,传入了指向错误类型的指针,这是与成功常量的比较(而不是0|1,这是C和世界其他地方之间痛苦的二分法!)
我不认为用goto更好地实现宏并不是太大的推动,无论如何,如果一个函数不止一次调用SUCCES_OR_RETURN,它可能是函数做得太多的线索。复杂的清理,或者返回可能是一种代码气味,您可以在这里阅读更多的http://eli.thegreenplace.net/2009/04/27/using-goto-for-error-handling-in-c/。
发布于 2014-05-05 14:23:23
我以前见过这种错误处理方式。我称它为错误-不经意的人工伪异常。
代码流主要是错误--忽略:您可以使用相同的错误标志在一行中调用3个函数,然后查看错误标志,看看是否发生了任何错误。
错误标志充当伪异常,一旦设置,我们就开始在正常代码流上“跳过”,但是这是手动完成的,而不是自动完成的。
如果您做了一些事情,而不关心是否发生了错误,您可以直接删除所产生的错误并继续进行。
ICU图书馆以类似的方式处理错误。
要做到这一点,同时最小化结构差异,更多的C++1y方法是修改代码以返回expected对象。
一个expected<T, Err>应该是一个T,如果出了什么问题,它将是一个Err类型。这可以实现为boost::variant和C++1Y的std::optional的混合。如果要对expected< T, Err > + U上的大多数算术操作进行重载以返回expected< decltype( std::declval<T&>() + std::declval<U>(), Err >,并执行了一些谨慎的auto操作,则至少可以允许算术表达式保持其结构。然后,您将检查该事实之后的错误。
另一方面,如果错误返回值基于其类型是可预测的,则可以创建一个类型,当转换到给定类型时会产生错误值。修改返回void的函数,以便在您访问它时返回某种错误对象。现在每个函数都可以
if (berror) return error_flag_value{};它至少能解决那个奇怪的;或-1;问题。
发布于 2014-05-05 13:14:12
如果您想使用完整的C++,答案将是更改异常的“无效返回值”.
#include <iostream>
#include <exception>
using std::exception;
struct error : exception { const char* what() const throw() override { return "unsuccessful"; } };
int fun1(int par1) {
if( par1 == 42 ) return 43;
throw error();
}
int funtoo(int a) {
fun1(a);
return 42;
}
void funthree(int b) {
funtoo(b);
std::cout << "Yuppi " << b << "\n";
}
int main() {
try {
funthree(42);
} catch(exception& e) {
std::cout << "Life has no meaning, because " << e.what() << "\n";
}
}这将打印Yuppi 42 (如果更改funthree(43)的调用funthree(42),则会打印Life has no meaning, because unsuccessful.)
(住在coliru)
https://stackoverflow.com/questions/23471187
复制相似问题