c ++异常和程序执行逻辑

时间:2010-05-06 01:31:47

标签: c++ exception-handling

我遇到过几个问题,但没有找到答案。

我想知道如何在C ++软件中实现异常处理,使其集中化并跟踪软件进度?

例如,我想在程序的四个阶段处理异常,并知道异常发生在该特定阶段:
1.初始化
2.脚本处理
3.计算
4.总结。

此时,我尝试了这个:

int main (...)
{
...
// start logging system
try {
    ...
    }
catch (exception &e)
  {
        cerr << "Error: " << e.what() << endl;
        cerr << "Could not start the logging system. Application terminated!\n";
        return -1;
  }
catch(...)
    {
        cerr << "Unknown error occured.\n";
        cerr << "Could not start the logging system. Application terminated!\n";
        return -2;
    }

// open script file and acquire data
try {
...
    }
catch (exception &e)
  {
        cerr << "Error: " << e.what() << endl;
        cerr << "Could not acquire input parameters. Application terminated!\n";
        return -1;
  }
catch(...)
    {
        cerr << "Unknown error occured.\n";
        cerr << "Could not acquire input parameters. Application terminated!\n";
        return -2;
    }
// computation
try {
...
}
...

这绝对不是集中的,而且看起来很愚蠢。 或者它根本不是一个好概念?

6 个答案:

答案 0 :(得分:3)

您可以保留一个包含程序状态的全局变量,并将其打印在catch块中。那么你只需要两个catch块,一个用于std :: exception,另一个用于其他一切。

答案 1 :(得分:2)

在我看来,您尝试使用异常(或多或少)替代日志记录。我想在这种情况下,将两者结合起来会好得多 - 特别是,我可能有一个小的异常处理程序将输出放在日志中,所以你的代码看起来像这样:

try { 
    // start logging system
}
catch (exception const &e) { std::cerr << e.what << "error starting logging"; }
catch (...) { std::cerr << "Unknown error starting logging"; }

try { 
    {   scoped_log("script processing");
        start_script();
    }
    {   scoped_log("computation");
        do_computation();
    }
    {   scoped_log("wrap up");
        wrap_up();
    }
}
catch(std::exception const &e) { log << "error: " << e.what() << "\n"; } 
catch(...) { log << "Unknown exception\n"; }  

其中“scoped_log”是一个简单的类,如:

class scoped_log { 
    std::string caption;
public: 
    scoped_log(std::string const &c) : caption(c) {
        log << "Starting:  " << caption << "\n";
    }
    ~scoped_log() { log << "Finished: " << caption << "\n"; }
};

这允许您集中大多数的异常处理。唯一的例外(没有双关语)是启动日志系统本身 - 显然你不能使用日志来报告启动日志系统的问题。

然而,一旦日志系统启动,事情就会简单得多 - 您可以使用日志记录和异常处理的组合来跟踪问题发生的时间。记住一个小细节:因为scoped_log是一个在退出范围时被破坏的对象(出于任何原因),所以日志的结构可能(至少在最初阶段)看起来有点误导 - 错误消息将跟随日志中的“finshed xxx”消息。例如,如果无法打开脚本文件,则您的日志可能如下所示:

starting script processing
finished script processing
error: could not open file: 'script.input'

至少IMO,如果你意识到这种情况,这不太可能导致问题。

答案 2 :(得分:1)

在我看来,例外情况应该(通常)有5个条件:

  1. 您可以合法地处理异常并继续正常(例如,您从用户输入中捕获了一个boost :: bad_lexical_cast,但可以通过向用户报告错误来恢复)。
  2. 您需要将异常从一个源转换为另一个源(例如,您的库使用另一个库作为纯实现细节,并希望将'socket_exception'转换为'service_exception'或类似的东西)。在.Net中,我通过抛出一个内部异常的新异常实例来做到这一点。在C ++中,为用户提供一致的接口会很有用,特别是如果您只是抛出从std :: exception派生的异常,但是依赖库会抛出非标准类型的异常(字符串, int,const char *,自定义类型等。)
  3. 你正在编写一个跨语言包装器。 C ++ / C,C ++ / Fortran等.C ++异常不会很好地跨越这些障碍,如果可能的话,最好将它们转换为目标运行时的错误处理工具。
  4. 你是主要人物,并希望从例外中获取一些细微的信息。在崩溃之前记录。如果你这样做,那么下一步该做什么就有两个主要阵营:退出(1)或抛出;并生成一个核心(在* nix上)。我的感情好坏......
  5. 很像主要的,围绕一个线程入口。可以帮助记录线程终止的原因,然后以适当的方式处理线程终止。

答案 3 :(得分:1)

集中异常处理的一种简单方法是创建一个简单的函数来处理异常,然后使用调用函数的泛型catch:

void processExceptions( std::string const & stage )
{
   std::cout << "Exception caught at stage " << stage << std::endl;
   try {
      throw; // rethrow the last caught exception
   }
   catch ( exception1 const & ) { 
      // do process 1
   }
   catch ( exception2 const & ) {
      // ...
   }
}
int main()
{
   try {
      initialize();
   }
   catch ( ... ) {
      processExceptions( "initialization" );
   }
   try {
      stage2();
   }
   catch ( ... ) {
      processExceptions( "stage2" );
   }
}

我从未使用过这种技术来识别异常何时被捕获,但如果相同的话,避免在许多地方重复异常处理代码是非常有用的。

请注意,如果在没有抛出异常的情况下调用该函数(在catch之外),您将得到未定义的行为,并且通常情况下您的应用程序将会死亡。

答案 4 :(得分:0)

另一种选择是具有不同的,由您定义的异常,然后您可以在一个中心位置处理,而不是使用不同的返回值。因此,当“无法获取输入参数”之类的异常发生时,您会抛出类似“invalid_parameters exception”的内容,并添加一些关于异常原因的更多上下文信息。然后在中央位置显示错误。

答案 5 :(得分:0)

如果您真的想要更集中化,可以定义自己的错误类,例如


class does_not_open {};  
class cannot_write {};

左右。你需要在不同的部分做更多的工作,例如,检查开放是否成功;如果没有,抛出does_not_open(等等)。但是在以这种方式组织自己之后,您可以将代码的整个主要部分放入以下形式:


try{  


}  

catch(does_not_open &e){  


}

catch(cannot_write &e){

- your code here -

}
catch(...){

- your code here -

}

不确定这会达到你所希望的......但是gl。 :)