c++ - 为什么 std 智能指针类型析构函数不继承指向对象的 noexcept dtor 状态

标签 c++ c++11 destructor smart-pointers noexcept

在 C++11 中,我的理解是默认情况下析构函数是隐式的 noexcept(true) ,除了:

如果我有一个类C有一个显式标记为 noexcept(false) 的析构函数(大概是因为它出于某种奇怪的原因抛出,我知道你不应该,为什么)然后是派生自 C 的任何类的析构函数或包含 C 类型的成员也变成noexcept(false) .

但是,一个包含std::shared_ptr<C>的类显然不会自动将其析构函数切换为 noexcept(false) , 包含 std::weak_ptr<C> 也是如此, std::unique_ptr<C>

这是一个完整的例子:

#include <type_traits>
#include <memory>

struct Normal {
    ~Normal() {
    }
};

struct ThrowsInDtor {
    ~ThrowsInDtor() noexcept(false) {
        throw 42;
    }
};

template<typename T>
struct Wrapper {
    T t;
};

template<typename T>
struct UniquePtrWrapper {
    std::unique_ptr<T> t;
};

template<typename T>
struct SharedPtrWrapper {
    std::shared_ptr<T> t;
};

static_assert(std::is_nothrow_destructible<Normal>::value, "A"); // OK
static_assert(!std::is_nothrow_destructible<ThrowsInDtor>::value, "B"); // OK

static_assert(std::is_nothrow_destructible<Wrapper<Normal>>::value, "C"); // OK
static_assert(!std::is_nothrow_destructible<Wrapper<ThrowsInDtor>>::value, "D"); // OK

static_assert(std::is_nothrow_destructible<UniquePtrWrapper<Normal>>::value, "E"); // OK
static_assert(!std::is_nothrow_destructible<UniquePtrWrapper<ThrowsInDtor>>::value, "F"); // FAILS

static_assert(std::is_nothrow_destructible<SharedPtrWrapper<Normal>>::value, "G"); // OK
static_assert(!std::is_nothrow_destructible<SharedPtrWrapper<ThrowsInDtor>>::value, "H"); // FAILS

F 和 H 失败对我来说似乎很奇怪。我原以为拥有/引用类型的析构函数的 noexcept 状态会传播到智能指针析构函数,大概是通过类似 noexcept(std::is_nothrow_destructible<T>::value) 的 noexcept 表达式。在智能指针析构函数声明上。

但是标准没有提到这一点,我看过的标准库代码也没有这样做。

有谁知道为什么标准智能指针不将实例化类型的 noexcept 析构函数状态传播到智能指针析构函数?

最佳答案

std::shared_ptr<T>旨在与不完整的 T 一起使用,因此在声明其析构函数时无法获取您要求的信息。此外,您还可以这样做:

std::shared_ptr<void> dummy = std::make_shared<T>(); // for some complete T

现在应该做什么noexceptstd::shared_ptr<void> ?这是来自 std::shared_ptr 的运行时信息的视角。

对于 std::unique_ptr , 有

20.7.1.2.2 unique_ptr destructor [unique.ptr.single.dtor]

1 ~unique_ptr();

Requires: The expression get_deleter()(get()) shall be well formed, shall have well-defined behavior, and shall not throw exceptions. [ Note: The use of default_delete requires T to be a complete type. —endnote]

这意味着删除器需要确保它不会抛出 - 这不一定一定取决于 T 的析构函数,即,当您使用空删除器时。

关于c++ - 为什么 std 智能指针类型析构函数不继承指向对象的 noexcept dtor 状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19528691/

相关文章:

c++ - std::chrono 中是否有设施来协助注入(inject) system_clock 进行单元测试

c++ - 这会做默认的 move 操作吗

c++ - 为什么调用析构函数

c++ - C++中的纯虚析构函数

c++ - boost multi_index_container 和内存碎片

c++ - 如何确定我在无线网络中连接的接入点的延迟和数据包丢失?

c++ - 删除除 'largest' 之外的所有 vector 元素

c++ - 使用 Cmake 的 RelWithDebInfo 作为默认构建类型

c++ - 标量删除析构函数

c++ - 使用虚空函数但没有编译错误的类中的运行时错误