为什么C++中的new不会在失败时返回NULL

NDe*_*iny 36 c++

为什么不new返回NULL失败?为什么它只在失败时抛出异常?

因为它在成功时返回指向对象的指针,为什么不在失败时呢?这种行为有什么具体原因吗?

Che*_*Alf 55

在C++中引入异常之前:

  • 失败new的表达式产生了一个nullpointer.

  • 在失败的构造函数中,指定了一个nullpointer this.

引入例外情况后:

  • 失败的普通new表达式会引发异常.

  • 在失败的构造函数中,会抛出异常.

一个区别是构造函数的失败报告现在也适用于创建没有动态分配的对象.

另一个区别是new现在使用-expressions的代码可以更简单,因为错误处理可以从每个这样的代码位置移出并集中.

旧的nullpointer-result行为仍可通过std::nothrow(包括<new>标题)获得.这意味着要检查每个地方new.因此,nullpointer结果与DRY原则相冲突,不要重复自己(冗余提供了无穷无尽的引入错误的机会).

  • +1是唯一一个(到目前为止)甚至讨论它背后的"为什么",而不只是解释两者都是可能的或者更常见的C++错误处理.... (7认同)

Naw*_*waz 29

这是设计的.在C++中,默认情况下抛出异常会通知每种类型的故障 - 但是,流是异常,默认情况下不会抛出异常(双关语).

您可以使用nothrow版本:

T *p = new (std::nothrow) T(args);

if ( p == nullptr ) //must check for nullity
{
     std::cout << "memory allocation failed" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

  • +1"for design"和*exception*pun - 仍然,我总是想知道是否为引发异常而做出异常不是因设计错误*... (4认同)

Fer*_*eak 14

只是一个历史记录,而不是这个问题的答案(有很多好的答案)......很久很久以前恐龙在地球上漫游而Turbo C++统治着C++程序员的世界,new实际上已经回归了NULL.引用当时的书(0bj3ct-0r13nt3d Pr0gr4mm1ng与ANSI和Turbo C++ - 标题故意混淆,以便没有人错误地读取它)第115页.

如果新运算符未能分配内存,则返回NULL,可用于检测新运算符的失败或成功.

因为这个遗留代码已经完成了大量的NULL检查...真正的噩梦让他们达到当前的标准......

但是,这是C++标准5.3.4/13中的一小部分:

[注意:除非使用非抛出异常规范(15.4)声明分配函数,否则它表示无法通过抛出std :: bad_alloc异常来分配存储(第15,18.6.2.1节); 否则返回非空指针.如果使用非抛出异常规范声明分配函数,则返回null以指示无法分配存储,否则返回非空指针.-end note]如果分配函数返回null,则不进行初始化,不应调用解除分配函数,并且new-expression的值应为null.

这告诉你,在某些特殊情况下,new可以返回NULL


Pei*_*Zhu 8

在C++中,运算符new不仅要分配一块内存,还要进行类构造.因此,在语义上,运算符new比函数更丰富malloc.通过例外,我们可以获得更好的信息,我们可以更好地处理施工失败.


Adr*_*thy 6

在评论中,你强调你想知道为什么这样 new设计.在我看来,这都是关于对象组合.

考虑一个类Foo,其中包含(除其他外)std :: vector.

class Foo {
  public:
    explicit Foo(std::size_t n) : m_vec(n, 'A') {}
    ...
  private:
    std::vector<char> m_vec;
    ...
};
Run Code Online (Sandbox Code Playgroud)

在动态内存中构造Foo时,有两个内存分配:一个是Foo本身,另一个是其向量的内容.如果其中任何一个失败,您需要确保没有泄漏,并且问题会报告给调用者.

Foo * pfoo = new Foo(desired_size);
Run Code Online (Sandbox Code Playgroud)

假设new在失败时返回空指针.如果Foo的分配失败,pfoo将被设置为空指针,您可以依靠它来进行错误检测.了不起.然后你有一些错误处理代码,如:

if (pfoo == nullptr) { ... }
Run Code Online (Sandbox Code Playgroud)

现在考虑嵌套对象.如果内容的分配m_vec失败,您必须检测并将其报告给调用代码,但是没有办法让您获得一个空指针传播到赋值pfoo.唯一的方法是让std :: vector抛出异常(对于任何类型的构造问题),因此我们刚刚添加的错误处理代码将是无用的,因为它正在寻找空指针而不是异常.

new射程std::bad_alloc可以让你把嵌套的动态内存分配失败你对待外部的方式相同.这是避免代码重复和错误的有效方法.

C++委员会可以new在分配失败时返回一个空指针,但是每个new用于内部存储器的构造函数都必须检测失败并将其转换为异常.因此,new默认情况下抛出简化了每个人的代码.

对于构造函数即使在分配失败时也可以做一些合理的事情,你可以显式地询问空指针std::nothrow然后处理错误(或者你可以捕获std::bad_alloc).

在旁边

还要考虑如果我们堆栈分配一个Foo会发生什么.

Foo foo(desired_size, 'B');
Run Code Online (Sandbox Code Playgroud)

如果我们以某种方式设法使构造问题返回一个空指针,调用代码将如何检测它?