如何组合std :: make_shared和new(std :: nothrow)

Adr*_*thy 15 c++ make-shared nothrow

C++的new有一个选项可以返回空指针,而不是在分配失败时抛出bad_alloc异常.

Foo * pf = new(std::nothrow) Foo(1, 2, 3);
Run Code Online (Sandbox Code Playgroud)

(是的,我理解这只会阻止new抛出bad_alloc;它不会阻止Foo的构造函数抛出异常.)

如果你想使用共享指针而不是原始指针,你通常应该使用make_shared,因为它对控制块的分配很聪明.

auto pf = std::make_shared<Foo>(1, 2, 3);
Run Code Online (Sandbox Code Playgroud)

make_shared封装了new,这使得(?)无法选择nothrow版本.因此,您似乎必须放弃make_shared并明确调用new.

std::shared_ptr<Foo> pf(new(std::nothrow) Foo(1, 2, 3));
Run Code Online (Sandbox Code Playgroud)

这消除了使用Foo分配控制块的优化,并且控制块分配可能独立于Foo分配而失败,但我不想关注它.让我们假设控制块很小,所以它的分配在实践中永远不会失败.这是为我担心的Foo分配空间的失败.

有没有办法获得make_shared的单一分配优势,同时保留在为Foo分配空间时简单地获取空指针而不是bad_alloc异常的能力?

Mar*_*k B 6

看起来allocate_shared,传入一个使用nothrownew 的分配器应该为你做的伎俩.

  • 投票否决,因为这会恕我直言,这违反了分配程序的要求。(第17.6.3.5节表28)如果系统内存不足,此解决方案肯定会出现严重错误。例如,MSVC12的allocate_shared()不检查allocate()返回的指针,并会愉快地在(void *)0处构造控制块。首次取消引用此指针的尝试很可能会失败。(幸运的是,在MSVC12上,这已经发生在`allocate_shared()`中)。 (2认同)
  • @MarkB在当前草案[表29](http://eel.is/c++draft/allocator.requirements#tab:utilities.allocator.requirements)中列出了表达式“ a.allocate(n)”的效果“ “为n个类型T的对象分配了内存,但是没有构造对象。allocate可能会引发适当的异常。” 无疑这不是很明确,但是它指出在`a.allocate()`之后分配了内存。没有选择不分配并返回`nullptr`。在这种情况下,后继条件不需要成立,这可能会引发异常。 (2认同)