在C++中测试"new"返回值是否有用?

28

我通常从不在C++中看到对“new”的测试,我想知道为什么。

Foo *f = new Foo;

//假设f已经被分配,为什么通常情况下没有人测试new的返回值?

6个回答

50

根据当前的标准,new不会返回NULL,而是会抛出一个std::bad_alloc异常。如果你不想让new抛出异常(遵循旧标准)而是希望它返回NULL,你应该在其后加上"(std::nothrow)"。

Foo* foo = new (std::nothrow) Foo;

当然,如果你使用的是非常老旧的或可能已经损坏的工具链,它就可能不遵循标准。


1
它从不返回NULL...然后你自己又否定了这个说法 :) 使用std::nothrow会使你的第一部分说法变成假的 :) - OJ.
它并不是错误的,只是有点不一致。"正常"版本的 new 永远不会返回 NULL。 - Gorpik
2
不过修正一下答案也无妨! - Richard Corden
3
MSVC <=2003是一个有问题的工具链。 - osgx
1
"根据旧标准"。那是哪个标准? - Lightness Races in Orbit
显示剩余2条评论

7

这完全取决于你使用的编译器。对于非MFC应用程序,VC++ 6及以下版本在new操作失败时会返回NULL。

当你在VC++ 6中使用STL时,问题变得更加复杂,因为STL遵循标准,它永远不会在需要获取一些内存时测试NULL,并且在内存紧张的情况下会发生什么...

因此,对于仍在使用VC++ 6和STL的人,请查看此文章以获得修复方法。 Don't Let Memory Allocation Failures Crash Your Legacy STL Application


5
  1. 默认情况下,new 会抛出 std::bad_alloc 异常。如果使用默认设置,则检查 null 指针已经过时,但需要处理异常。这种默认行为与 C++ 异常安全范例一致 - 它通常提供对象要么构造成功,要么未分配。

  2. 如果你使用 new (std::nothrow) 覆盖默认设置,则需要检查 null 指针。"New" 同时分配和提交页面,因此可能会耗尽内存,原因可能是由于页描述符不足或没有可用的物理内存。

  3. 研究您操作系统的内存管理。C/C++ 参考机器不知道您的操作系统如何管理内存,因此仅依赖语言是不安全的。例如,有关内存分配失败的示例,请阅读 C malloc() + Linux 过度承诺。


4

这完全取决于代码针对的 C++ 版本。

C++ 规范已经很长一段时间以来声明,默认情况下,new 失败会导致 C++ 异常,因此任何执行测试的代码都将是完全多余的。

现今大多数编程也瞄准虚拟内存操作系统,其中几乎不可能耗尽内存,并且内存不足的情况非常致命,只需让应用程序在下一个 NULL 访问时崩溃即可终止。

只有在嵌入式编程中,异常处理被认为是太过沉重负担且内存非常有限时,程序员才费心检查 new 失败。


捕获异常并将数据保存到磁盘,可能比让应用程序崩溃更好的方式... - Chris M.
但是怎么办呢?现代C++中到处都是对象创建。当一个“new”失败时,强烈预期后续的new尝试也会失败。这意味着将数据持久化到磁盘的尝试也会失败。 - Chris Becke
1
在计算机上几乎不可能耗尽内存的地方,我不同意这一点。在32位进程中很容易用尽虚拟内存,在Windows系统中您只能获得2GB的地址空间。任何涉及取样数据(如视频、医学等)的领域都可能轻易填满或使其碎片化,导致分配失败。 - morechilli
1
这完全取决于您的应用程序领域。对于大型数据集,使用STL类型容器是很常见的。个人而言,在接近分配足够内存以耗尽虚拟内存空间时,我会使用本地分配器,并检查是否失败。 - Chris Becke
1
@Chris Becke:“但是怎么做呢?”一种方法是预先分配“足够大”的内存块并注册一个新的处理程序,该处理程序释放它并抛出bad_alloc异常。应用程序捕获异常,现在有“足够”的内存可用于打印诊断信息并干净地退出。 - Steve Jessop
显然,“足够”的值取决于C++实现以及应用程序,因此可能无法获得绝对的确定性,但通常可以做得比仅因未处理的异常而终止要好得多:至少可以确保堆栈被解开。 - Steve Jessop

3

此处所述:

在符合ISO C++标准的编译器中,如果内存不足以进行分配,则代码会抛出std::bad_alloc类型的异常。直到错误被try-catch块处理或程序异常退出之前,所有后续的代码都将被中止。程序不需要检查指针的值;如果没有抛出异常,则分配成功。


0
通常情况下,由于Visual Studio现在按照标准的方式抛出异常,因此没有人会测试新代码中new操作符的返回值。
对于旧代码,如果已经进行了一些hack以避免抛出异常,那么最好还是进行测试。

这个问题暗示了环境是 MS DevStudio? - Chris Becke
没有任何返回。但是如果Visual Studio没有得到这个修复,那么发帖人就不太可能处于这种情况下:“我通常从不在C++中看到新的测试”。所以我解释了一下。 - Windows programmer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接