Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Here is very basic code:

#include <memory>

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

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

Compiled as follows:

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

When compiling with libc++, it failes with:

/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();

I thought it might be a bug in libc++, but wanted to check here before I file a bug.

like image 526
Innocent Bystander Avatar asked May 04 '17 19:05

Innocent Bystander


1 Answers

the question(s) boil down to:

  • Should this compile? A: Maybe
  • What happens if you run it? A: You get undefined behavior.

AS @T.C. says, [res.on.functions]/2 states:

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.

Standard-ese aside, throwing from a destructor has been a bad idea for a long, long time (at least since C++98). If there is an exception in flight, and you throw another exception during stack unwinding, that's a quick trip to std::terminate().

like image 193
Marshall Clow Avatar answered Nov 15 '22 14:11

Marshall Clow