摆脱丑陋的C结构

Fer*_*eak 4 c c++ macros c++11

我继承了一段(大)代码,它有一个错误跟踪机制,它们将布尔变量传递给它们调用的所有方法,并且在执行的各个阶段出现错误,方法停止并返回,有时是默认值.

类似的东西(BEFORE):

#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";
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,这是C和C++代码的混合,与项目的完全一致.

现在,来了一个C魔术:"某人"某处定义了一个宏:

#define SUCCES_OR_RETURN  if(!psuccess) return
Run Code Online (Sandbox Code Playgroud)

上面的程序变成(后):

#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";
    }
}
Run Code Online (Sandbox Code Playgroud)

问题是:我想知道是否有更好的方法来处理这种错误跟踪或我必须忍受这个.我个人不喜欢滥用C宏观SUCCES_OR_RETURN.一旦用参数调用它,而在其他情况下它被调用,感觉就像一个真实的return声明,但我没有找到任何更好的解决方案,这个古老的设计.

请注意,由于平台限制,我们有几个限制,但无论如何,我都愿意听到有关这两个的意见:

  • 抛出异常.代码是C和C++函数的混合,相互调用,编译器类型不支持throw(在语法中接受但不对其执行任何操作,只是警告).此解决方案是在C++环境中解决此问题的标准方法.
  • C++ 11的特性,这是一个微小的嵌入式平台,带有一个模糊而古老的"几乎"C++编译器,它不支持最新的C++特性.但是为了将来的参考,我很好奇C++ 11提供了什么.
  • 模板魔术.编译器在理解复杂的模板化问题时遇到了问题,但我仍然愿意看到您能提出的任何解决方案.

编辑

另外,正如@BlueMoon在推荐中所建议的那样,创建一个全局变量是行不通的,因为在函数链的最开始,调用success变量是一个类的成员变量,并且创建了这个类的几个对象,每个对象都是需要报告其成功状态:)

Lee*_*ley 5

这里有混合C和C++错误处理策略的很大细分:

引用链接的文章,您的选择主要归结为:

  • 从可能失败的函数返回错误代码.
  • 提供Windows GetLastError()或OpenGL 等功能glGetError()来检索最近出现的错误代码.
  • 提供包含最新错误的全局(好的,希望是线程局部的)变量,如POSIX的errno.
  • 提供一个函数来返回有关错误的更多信息,可能与上述方法之一一起,如POSIX的strerror功能.
  • 允许客户端在发生错误时注册回调,如GLFW glfwSetErrorCallback.
  • 使用特定于操作系统的机制,如结构化异常处理.
  • 将错误写入日志文件,stderr或其他位置.
  • 只是断言()或以其他方式在发生错误时终止程序.

看起来你继承的代码的作者选择了一种相当奇怪的方式,将一个指向布尔[sic]的指针传递给函数,看起来很不寻常.

这篇文章有一些很好的例子,我个人喜欢这种风格:

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!
}
Run Code Online (Sandbox Code Playgroud)

在这里你可以获得一些东西,传递指针到错误类型,与成功常数的比较(而不是0|1C与世界其他地方之间的痛苦二分法!).

我认为goto,如果一个函数SUCCES_OR_RETURN不止一次调用,你的宏可能更好地用a实现,这并不是一个太大的推动,它可能是一个线索,该函数也在做许多.复杂的清理,或返回可能是代码气味,你可以在这里阅读更多http://eli.thegreenplace.net/2009/04/27/using-goto-for-error-handling-in-c/