在 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
现在应该做什么noexcept
说 std::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 ofdefault_delete
requiresT
to be a complete type. —endnote]
这意味着删除器需要确保它不会抛出 - 这不一定一定取决于 T
的析构函数,即,当您使用空删除器时。
关于c++ - 为什么 std 智能指针类型析构函数不继承指向对象的 noexcept dtor 状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19528691/