【问题标题】:How can some code be run each time an exception is thrown in a Visual C++ program?每次在 Visual C++ 程序中引发异常时,如何运行一些代码?
【发布时间】:2010-11-19 08:54:04
【问题描述】:

如果在 C++ 程序中引发异常,则控件要么转移到异常处理程序,要么调用 terminate()

即使程序从处理程序内部(或来自terminate() 处理程序)发出一些可能为时已晚的诊断信息 - 最多的值在调用堆栈中发生异常的位置,不在处理程序中。

在 Windows 上,可以使用 [StackWalk64()]1 函数获取调用堆栈。关键是如何在适当的时候调用那个函数。

有没有办法让 Visual C++ 程序在每次抛出异常(或未设置处理程序的异常)时执行一些用户代码?

【问题讨论】:

    标签: c++ visual-c++ exception exception-handling


    【解决方案1】:

    如果您想在引发 SEH 异常时进行处理,例如发生访问冲突时,那么您可以简单地捕获 SEH 异常(使用 __finally 或转换为 C++ 异常(参见 @987654321 @)) 并访问异常中的上下文,该上下文是引发异常时的上下文。然后,您可以使用 StackWalker 或小型转储生成调用堆栈。恕我直言,最好生成一个小型转储。

    如果您想在抛出 C++ 异常时捕获它们,并且您无权访问 C++ 异常类的源代码,那么您需要更巧妙一些。我通过在自定义调试器下运行目标进程来解决这个问题 - 使用 Debug API(请参阅here),它会收到有关何时引发异常的通知。此时,您可以创建目标进程的小型转储或调用堆栈。

    【讨论】:

      【解决方案2】:

      在 Windows 上,我使用 SetUnhandledExceptionFilterMiniDumpWriteDump 来生成小型转储。

      【讨论】:

        【解决方案3】:

        __try, __except 非常有帮助。

        【讨论】:

          【解决方案4】:

          有没有办法让 Visual C++ 程序在每次抛出异常(或未设置处理程序的异常)时执行一些用户代码?

          将该代码放入异常基类的构造函数中。

          【讨论】:

          • 好主意,但如果抛出一些不相关的异常将无济于事。
          • @sharptooth:可以进行异常翻译。在我自己的异常类型中包装库异常(例如来自 Boost)对我来说总是一个好主意。
          • @Daniel Lidström:是的,异常翻译很棒,但了解原始异常的来源通常很有用。
          【解决方案5】:

          当语言不支持它,而你没有它就活不下去时,hack... :-/

          #include <iostream>
          #include <stdexcept>
          
          namespace Throw_From
          {
              struct Line
              {
                  Line& set(int x) { x_ = x; return *this; }
                  int x_;
          
                  template <typename T>
                  void operator=(const T& t) const
                  {                                                                       
                      throw t;
                  }                                                                       
              };                                                                          
              Line line;                                                                  
          }                                                                               
          
          #define throw Throw_From::line.set(__LINE__) =                                  
          
          void fn2()                                                                      
          {                                                                               
              throw std::runtime_error("abc");                                            
          }                                                                               
          
          void fn1()                                                                      
          {                                                                               
              fn2();                                                                      
          }                                                                               
          
          int main()                                                                      
          {                                                                               
              try
              {
                  fn1();
              }
              catch (const std::runtime_error& x)
              {
                  std::cout << Throw_From::line.x_ << '\n';
              }
          }
          

          【讨论】:

          • 这不会像写的那样工作,因为throw 的优先级高于,;你最终会抛出Throw_From::line,而不是"ouch"
          • 实际上,这还有一个更大的问题,即如果包含任何标准库头文件,则不允许定义与关键字词法相同的宏,因此#define throw whatever 是不可能的。
          • @James:通常当人们开始考虑在异常情况下调用特定于平台的堆栈转储时,他们并不关心可移植性或标准,而是会检查他们的标头以查看它是否有效。少恶之类的。 (嗯...不能重载运算符,- 太晚了)
          • #define THROW(E) (do_stuff(), (throw E))
          • @Tony:那些人通过未检测到的 UB 使情况变得更糟,从而使情况变得更糟。
          【解决方案6】:

          This 是一篇很棒的文章,介绍了如何在 Visual C++ 中捕获所有不同类型的异常。
          它还为您提供了一个有助于调试的故障转储。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-08-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多