【发布时间】:2022-11-19 02:57:05
【问题描述】:
我知道根据 C++ 标准,如果 new 无法分配内存,它应该抛出 std::bad_alloc 异常。但我听说有些编译器如 VC6(或 CRT 实现?)不遵守它。这是真的 ?我问这个是因为在每条新语句之后检查 NULL 会使代码看起来非常难看。
【问题讨论】:
标签: c++ visual-c++ memory-management new-operator visual-c++-6
我知道根据 C++ 标准,如果 new 无法分配内存,它应该抛出 std::bad_alloc 异常。但我听说有些编译器如 VC6(或 CRT 实现?)不遵守它。这是真的 ?我问这个是因为在每条新语句之后检查 NULL 会使代码看起来非常难看。
【问题讨论】:
标签: c++ visual-c++ memory-management new-operator visual-c++-6
VC6 在这方面默认是不兼容的。 VC6 的new 返回0(或NULL)。
这是 Microsoft 关于此问题的知识库文章以及他们建议的使用自定义 new 处理程序的解决方法:
如果您有为 VC6 行为编写的旧代码,则可以通过链接到名为 nothrownew.obj 的目标文件来使用较新的 MSVC 编译器(如 7.0 及更高版本)获得相同的行为。在 7.0 和 7.1 编译器(VS2002 和 VS2003)中实际上有一个 fairly complicated set of rules 来确定它们是默认不抛出还是抛出 new。
8.0 (VS2005) 中的 MS cleaned this up 似乎总是默认为 throwing new,除非您特别链接到 nothrownew.obj。
请注意,您可以使用std::nothrow参数指定您希望new返回0而不是抛出std::bad_alloc:
SomeType *p = new(std::nothrow) SomeType;
这似乎在 VC6 中有效,因此它可能是一种或多或少机械地修复代码以与所有编译器一起工作的方法,因此您不必重新处理现有的错误处理。
【讨论】:
我想补充一点(有点争议)的观点,即在分配尝试后检查 NULL 几乎是徒劳的。如果您的程序曾经遇到这种情况,您很可能除了快速退出之外别无他法。很可能任何后续的分配尝试也会失败。
如果不检查 NULL,您的后续代码将尝试取消引用 NULL 指针,这往往会以相对独特(且易于调试)的退出条件快速退出程序。
我并不是要说服您不要检查 NULL,这当然是一种认真的编程。但是你不会从中获益太多,除非在非常特殊的情况下你可以存储一些恢复信息(无需分配更多内存),或者释放不太重要的内存等。但这些情况对大多数人来说相对较少。
鉴于此,我只相信编译器会亲自抛出 bad_alloc - 至少在大多数情况下。
【讨论】:
基于 C++ 规范,当你只使用没有参数的普通 new 时,它总是会抛出 std::bad_alloc ,但当然可能有一些不兼容的编译器。
不过,我不会编写与非 C++ 兼容编译器兼容的代码。 VC6 在这方面就是其中之一。
删除它们后始终将指针设置为 NULL 是一种很好的做法。因此,仍然需要检查 NULL。
话虽这么说,这里有几个清理代码的选项:
选项 1:设置您自己的新处理程序
清理代码的安全方法是先致电:set_new_handler。
然后你可以在你的处理程序中检查 NULL 并在返回 NULL 时抛出 std::bad_alloc 。
如果您更喜欢异常,那么这是您最好的选择。如果您想更好地返回 NULL,那么您也可以通过在新处理程序中执行 catch 来实现。
选项 2:使用重载的 new
C++标准头文件定义了一个空的struct nothrow。您可以在 new 中使用此结构的对象来获取始终返回 NULL 的重载版本。
void* operator new (size_t size, const std::nothrow_t &);
void* operator new[] (void *v, const std::nothrow_t &nt);
所以在你的代码中:
char *p = new(std::nothrow) char[1024];
【讨论】: