【问题标题】:With "-fno-exceptions", what happens with "new T"?使用“-fno-exceptions”,“new T”会发生什么?
【发布时间】:2011-05-18 18:46:16
【问题描述】:

我想知道,如果我使用-fno-exceptions 选项来禁用异常处理来编译我的程序,new T 还会抛出bad_alloc 吗?

或者编译器(GCC 和 clang 支持该选项)是否会将 new T 的使用隐式转换为 new (nothrow) T

【问题讨论】:

  • 有趣的问题。但是,为什么要禁用它?
  • 我不想禁用它:)
  • 只是好奇,您是否正在处理经常抛出 bad_alloc 的代码?
  • 我不处理任何代码。我只是在处理空中的想法。
  • 由于 C++ 标准不考虑这种情况,并且由于许多标准库实现假设(由于标准)分配器总是返回有效的内存块(这是有保证的),你将不得不放弃在这样一个程序中的标准库......因此提供您自己的newdelete,我猜。

标签: c++ exception


【解决方案1】:

按照我的理解,operator new 是由 libstdc++ 定义的。如果您现在使用-fno-exceptions 编译您自己的代码,您将无法捕获任何异常,但您仍将链接到会引发异常的普通版本的 libstdc++。

所以是的,new T 会抛出异常,即使是 -fno-exception

但是,如果您也使用 -fno-exception 编译 libstdc++,事情就会变得不同。现在,new T 不能抛出异常,但是,如果我读到 the libstdc++ manual right,它将改为调用 abort()

看来,如果您希望 new T 在失败时返回 NULL,唯一的方法是明确指定 nothrow...

【讨论】:

  • @nos 这与已接受的答案形成鲜明对比,并且更详细地显示了上面cat bad_alloc.cpp 的情况。
【解决方案2】:

我无法对 -fno-exceptions 的所有好处给出明确的答案,只是在 32 位 linux 机器上的观察结果,gcc 4.5.1 - bad_alloc 在有和没有-fno-exceptions的情况下都会抛出

[21:38:35 1 ~/tmp] $ cat bad_alloc.cpp

int main()
{
    char* c = new char[4000000000U];
}
[21:38:58 1 ~/tmp] $ g++ bad_alloc.cpp
[21:39:06 1 ~/tmp] $ ./a.out
terminate called after throwing an instance of 'std::bad_alloc'
  what():  std::bad_alloc
Aborted
[21:39:07 1 ~/tmp] $ g++ -fno-exceptions bad_alloc.cpp
[21:39:16 1 ~/tmp] $ ./a.out
terminate called after throwing an instance of 'std::bad_alloc'
  what():  std::bad_alloc
Aborted

【讨论】:

  • 您不需要使用-fno-exceptions 重新构建 C++ 标准库以获得完全期望的结果吗?
  • 当异常被禁用时,Clang 通过 throw 停止代码编译,GCC 是否有类似的行为?
【解决方案3】:

这不是一个确定的答案,但GCC Manual(请参阅“不做”部分)有这个:

在详细说明库支持之前 对于-fno-exceptions,首先是通过 注意这个标志时丢失的东西 被使用:它将打破异常 试图通过编译的代码 与-fno-exceptions 是否 该代码有任何尝试或捕获 结构体。如果你可能有一些 抛出的代码,你不应该使用 -fno-exceptions.

按照我的阅读方式,您可能必须明确要求new 的 nothrow 版本是完全安全的。

【讨论】:

【解决方案4】:

在许多异常处理系统中,如果例程“foo”调用“bar”,而后者又调用“moo”,并且“moo”抛出异常,则该异常可以干净地返回“foo”的唯一方法是“bar”是否有处理异常的代码。即使“bar”会让异常传播而不被捕获,它通常也必须确保其局部变量在允许执行离开范围之前被正确销毁。这将需要在“bar”中添加额外的代码;在大多数系统中,即使没有抛出异常,也必须执行其中一些代码。

顺便说一句,在某些 ARM 处理器(例如 Cortex M3 或在 ARM 模式下运行的 Arm7)上,如果调用者也将在 ARM 模式下运行,则可以通过使用“正常”子程序返回到 LR+4(超出正常返回地址的四个字节)并有一个异常退出到 LR(这将是一个 4 字节的分支指令)。不过,这种行为与 ARM 上的正常做法相反,而且这种设计不能很好地移植到 Cortex M0。

【讨论】:

  • 那么,鉴于这些信息,GCC 是否会将new 转换为new (nothrow)? ;-p
猜你喜欢
  • 2018-02-06
  • 2017-01-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-03
  • 2011-03-22
  • 2020-11-10
相关资源
最近更新 更多