【问题标题】:How to combine std::make_shared and new(std::nothrow)如何结合 std::make_shared 和 new(std::nothrow)
【发布时间】:2014-04-26 00:21:00
【问题描述】:

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

Foo * pf = new(std::nothrow) Foo(1, 2, 3);

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

如果您想使用共享指针而不是原始指针,您通常应该使用 make_shared,因为它可以巧妙地分配控制块。

auto pf = std::make_shared<Foo>(1, 2, 3);

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

std::shared_ptr<Foo> pf(new(std::nothrow) Foo(1, 2, 3));

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

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

【问题讨论】:

  • 您可能需要复制make_shared 的代码,然后根据需要进行修改。

标签: c++ make-shared nothrow


【解决方案1】:

看起来像allocate_shared,传入一个使用nothrow new 的分配器应该可以解决问题。

【讨论】:

  • 投了反对票,因为恕我直言,这会破坏分配器的要求。 (§17.6.3.5 表 28)如果系统内存不足,这个解决方案肯定会出错。例如,MSVC12 的allocate_shared() 不会检查allocate() 返回的指针,并且会很乐意在(void*)0 处构造控制块。第一次取消引用该指针的尝试很可能会失败。 (幸运的是,在 MSVC12 上,allocate_shared() 已经发生了这种情况。
  • @Matthäus Brandl 我在该表(C++11 草案标准)中没有看到任何会导致这违反分配器要求的内容,您能详细说明一下吗?
  • @MarkB 在当前的草案table 29 中列出了表达式a.allocate(n) 的效果“内存已分配给T 类型的n 个对象但未构造对象。分配可能引发适当的异常.”。这无疑不是很明确,但它指出在分配a.allocate() 内存之后。没有选择不分配和返回nullptr。它可能会抛出一个异常,在这种情况下后置条件不需要成立。
  • 同时an according question被问到the accepted answer在哪里得出相同的结论。
【解决方案2】:

只需自定义 nake_foo 并捕获异常:

#include <memory>

struct Foo {
    Foo(int, int, int) { throw std::bad_alloc(); }
};

std::shared_ptr<Foo> make_foo(int a, int b, int c) {
    try { return std::make_shared<Foo>(a, b, c); }
    catch (const std::bad_alloc&) { return std::shared_ptr<Foo>(); }
}

【讨论】:

    猜你喜欢
    • 2013-02-23
    • 1970-01-01
    • 2014-08-10
    • 1970-01-01
    • 2015-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多