std::make_shared 抛出 dtor 和 libc++ 无法编译

std::make_shared with throwing dtor and libc++ doesn't compile

这是非常基本的代码:

#include <memory>

class foo
{
public:
    ~foo() noexcept(false) { }
};

int main()
{
    auto x = std::make_shared<foo>();
    return 0;
}

编译如下:

g++ -std=c++11 test.cpp          <-- OK
clang++ -std=c++11 test.cpp          <-- OK
clang++ -std=c++11 -stdlib=libc++ test.cpp          <-- FAIL

使用 libc++ 编译时,失败并显示:

/usr/bin/../include/c++/v1/memory:3793:7: error: exception specification of overriding function is more lax than base version
class __shared_ptr_emplace
    ^
/usr/bin/../include/c++/v1/memory:4423:26: note: in instantiation of template class 'std::__1::__shared_ptr_emplace<foo,
    std::__1::allocator<foo> >' requested here
    ::new(__hold2.get()) _CntrlBlk(__a2, _VSTD::forward<_Args>(__args)...);
                        ^
/usr/bin/../include/c++/v1/memory:4787:29: note: in instantiation of function template specialization
    'std::__1::shared_ptr<foo>::make_shared<>' requested here
    return shared_ptr<_Tp>::make_shared(_VSTD::forward<_Args>(__args)...);
                            ^
exc.cpp:11:19: note: in instantiation of function template specialization 'std::__1::make_shared<foo>' requested here
    auto x = std::make_shared<foo>();
                ^
/usr/bin/../include/c++/v1/memory:3719:13: note: overridden virtual function is here
    virtual ~__shared_weak_count();

我认为这可能是 libc++ 中的错误,但我想在提交错误之前检查这里。

问题归结为:

  • 这应该编译吗?答:也许
  • 如果你 运行 会怎样? A:你得到未定义的行为。

AS @T.C。说,[res.on.functions]/2 状态:

In certain cases (replacement functions, handler functions, operations on types used to instantiate standard library template components), the C++ standard library depends on components supplied by a C++ program. If these components do not meet their requirements, this International Standard places no requirements on the implementation.

In particular, the effects are undefined in the following cases:

[skip]

-- if any replacement function or handler function or destructor operation exits via an exception, unless specifically allowed in the applicable Required behavior: paragraph.

撇开标准语言不谈,从析构函数中抛出异常在很长很长一段时间内都是一个坏主意(至少从 C++98 开始是这样)。如果在运行中出现异常,并且您在堆栈展开期间抛出另一个异常,那么可以快速到达 std::terminate().