【问题标题】:What exactly will happen if I disable C++ exceptions in a project?如果我在项目中禁用 C++ 异常,究竟会发生什么?
【发布时间】:2009-06-03 04:42:33
【问题描述】:

Visual C++ 有一个编译器设置“启用 C++ 异常”,可以设置为“否”。如果我这样设置会发生什么?我的代码从不显式抛出或捕获异常(因此第一个抛出的异常无论如何都会终止程序)并且不依赖堆栈展开 - 我是否应该期望重新编译的程序有更多不希望的行为?

【问题讨论】:

  • 我猜你正在追求性能提升。你试过了吗?在您的程序中禁用异常有多大帮助?
  • Visual C++ 是否支持 WG21 宏:__cpp_exceptions?

标签: c++ exception exception-handling


【解决方案1】:

MSDN documentation of the setting 解释了不同的异常模式,甚至给出了代码示例来展示不同模式之间的区别。此外,this article 可能很有趣,尽管它已经很老了。

底线:该选项基本上启用或禁用跟踪所有对象的寿命。这样的跟踪是必需的,因为在发生异常的情况下,需要调用所有适当的析构函数,必须展开堆栈,并进行大量清理工作。此类跟踪需要组织开销(= 额外代码) - 这可以通过将选项设置为“否”来取消。

我自己没有尝试过,但是如果选项设置为“否”,您似乎仍然可以throwcatch 异常,但是缺少清理和展开,这可能非常糟糕后果(不推荐;)..

【讨论】:

  • 您当然仍然可以投掷和接球 - 但您需要自己管理生命周期。您在模块大小方面获得了相当大的优势,如果您对此感到担忧,那么这可能是这样做的理由
【解决方案2】:

当 C++ 对象因异常而超出范围时,编译器将省略析构函数和其他堆栈展开代码。

换句话说,它省去了一堆清理代码。这will significantly improve performance,但如果确实抛出异常,也会导致严重的邪恶。 (如果您不相信我,请自行计时。)

性能差异并不是禁用异常的真正理由,除非在某些关键应用程序中您绝对有义务这样做。

【讨论】:

  • 点击该死的链接,亲眼看看。如果你不相信,那就自己计时。我已经在我的平台上完成了。这是有代价的。
  • 但是由于我的代码中没有 try-catch,所以第一个抛出的异常只会导致程序终止。我没有看到任何比我已经拥有的更邪恶的东西。
  • 它减少了代码大小,提高了缓存性能,并删除了很多分支,也提高了性能。
  • 不要假设在没有异常支持的程序中抛出异常只会优雅地终止程序。根据机制的实现方式,如果发生抛出并且 RTL 不包含异常支持,您将出现不可预知的行为。考虑做一个老式的 longjmp 传递一个没有用以前的 setjmp 初始化的变量。
  • IIRC,性能差异的主要原因是编译器在启用异常处理时必须关闭一些优化。也就是说,它不能重新排列指令,以便在子程序出现异常时部分构造对象。
【解决方案3】:

当您对“启用 C++ 异常”说“否”时,则不会选择编译器的异常处理同步模型(/GX 或 /EHsc)。在这种模式下,不会启用展开语义。也就是说,一个自动存储在框架中的对象,在执行 throw 的函数和捕获 throw 的函数之间,不会被销毁。

有关异常处理的更多详细信息,您可以参考 MSDN 或 A Visual C++ Exception FAQ

class Test
{
public:

    Test()
    {
        printf("Test::constructor");
    }
    ~Test()
    {
        printf("Test::Destructor");
    }

};


int _tmain(int argc, _TCHAR* argv[])
{
    int a;

 try
   {
     Test a;
     int* p = 0;
     *p = 0; // Cause access violation
   }
   catch (...)
   {
      printf("Caught access violation"); 
   }
    return 0;
}

如果不处理异常,输出将是:

Test::constructor
Caught access violation

【讨论】:

  • MSVC 的默认设置是“否”吗?使用 GCC 和 Clang,它们默认开启,并使用标志关闭(即 -fno-exceptions)。
【解决方案4】:

我使用过的代码总是关闭异常。我还没有看到损坏或资源浪费的问题。

我认为异常通常不太适合 c++。堆栈爆破,尤其是在缺乏 GC 的情况下,使整个异常变得痛苦。然后是关于“异常”的真正含义与失败的可能性相比的争论。

【讨论】:

    【解决方案5】:

    您仍然可以访问结构化异常处理 (SEH),它可以由 __try、__except 和 __finally 处理。

    C++ 异常处理只是建立在 SEH 之上的类实现。

    如果您尝试在具有 SEH 异常处理程序的函数中实例化类(抱怨需要展开的对象,即类),编译器也会抱怨,这可能有点混乱,但有一些方法可以绕过它。

    【讨论】:

      【解决方案6】:

      就标准 C++ 而言,您将获得未定义的行为。 C++ 标准不允许全局关闭异常的可能性,并且某些标准库操作被定义为在某些情况下抛出异常。

      【讨论】:

      • 好的,那么禁用 C++ 异常的正当理由是什么?看起来这只是一种以一种或另一种方式处理未定义行为的直接方式。
      • 我认为没有正当理由 - 关闭异常与关闭整数一样有意义。
      • 禁用 C++ 异常可以在内核模式下使用 C++ 的受限子集。
      • 关闭异常会使许多其他 C++ 功能几乎无法使用(例如,ctors、模板),您不妨使用 C,恕我直言。至少 C 是一种标准化语言,而“C++ 子集”不是。
      • 据我所知,它的实现定义了 C++ 的独立实现是否支持异常。
      【解决方案7】:

      如果operator new分配内存失败,我相信它会返回NULL而不是抛出std::bad_alloc异常。

      如果您对引发异常的第三方库进行任何调用,将会导致很多问题。

      【讨论】:

      • 我希望它不会造成比我现在更糟糕的情况。由于我没有捕获异常,因此在任何地方抛出的任何异常都会立即导致我的程序终止。我错过了什么吗?
      猜你喜欢
      • 2023-04-01
      • 2014-03-03
      • 2023-03-29
      • 1970-01-01
      • 2015-12-25
      • 2019-10-12
      • 2010-11-18
      • 2015-10-23
      • 2011-01-18
      相关资源
      最近更新 更多