我知道根据 C++ 标准,如果 new 无法分配内存,它应该抛出 std::bad_alloc 异常。但我听说一些编译器,如 VC6(或 CRT 实现?)不遵守它。这是真的 ?我问这个是因为在每个新语句之后检查 NULL 会使代码看起来非常难看。
3 回答
VC6 在这方面默认是不合规的。VC6 的new
返回0
(或NULL
)。
这是 Microsoft 关于此问题的知识库文章以及他们建议的使用自定义new
处理程序的解决方法:
如果您有为 VC6 行为编写的旧代码,您可以通过链接一个名为nothrownew.obj
. 实际上,在 7.0 和 7.1 编译器(VS2002 和 VS2003)中有一组相当复杂的规则来确定它们是默认为 non-throwing 还是 throwing new
。
似乎MS 在 8.0 (VS2005) 中对此进行了清理——现在它始终默认为 throwing new,除非您特别链接到nothrownew.obj
.
请注意,您可以使用参数指定要new
返回0
而不是抛出:std::bad_alloc
std::nothrow
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++ 标准头文件定义了一个空的结构 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];