【问题标题】:std::make_shared with throwing dtor and libc++ doesn't compile抛出 dtor 和 libc++ 的 std::make_shared 无法编译
【发布时间】:2017-05-04 19:23:13
【问题描述】:

这是非常基本的代码:

#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++ 中的一个错误,但在我提交错误之前想在这里检查一下。

【问题讨论】:

  • 不知道标准是怎么说的——但是投掷 dtor 是完全错误的。
  • 这背后有动机吗?
  • @Mordachai 谢谢,但这与问题无关
  • @Mordachai 你无法获得析构函数的地址。
  • @Mordachai 是什么让您认为shared_ptr 存储了指向类型析构函数的指针?它有一个指向自定义可调用删除器的指针,但这不是一回事。

标签: c++ c++11 g++ clang++ libc++


【解决方案1】:

问题归结为:

  • 应该编译吗?答:也许
  • 如果你运行它会发生什么?答:您会得到未定义的行为。

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

在某些情况下(替换函数、处理函数、对用于实例化标准库模板组件的类型的操作),C++ 标准库依赖于 C++ 程序提供的组件。如果这些组件不满足其要求,则本国际标准对实施没有任何要求。

特别是在以下情况下效果是不确定的:

[跳过]

-- 如果任何替换函数或处理函数或析构函数操作通过异常退出,除非在适用的必需行为: 段落中明确允许。

抛开标准语言不谈,从析构函数中抛出一直是个坏主意(至少从 C++98 开始)。如果在运行中发生异常,并且您在堆栈展开期间抛出另一个异常,则可以快速访问std::terminate()

【讨论】:

  • 好吧,OP 的代码应该可以编译和工作。要求是 dtor not throw,而不是 noexcept.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-02-15
  • 1970-01-01
  • 1970-01-01
  • 2013-03-26
  • 1970-01-01
  • 2014-08-10
  • 1970-01-01
相关资源
最近更新 更多