在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::unique_ptr
,然而,它需要在析构函数被实例化和调用的时候类型是完整的。 - Xeostd::shared_ptr
也可能是这样。无论如何,我已经更新了答案。 - Daniel Freystd::unique_ptr
本身的析构函数,抱歉造成困惑。 - Xeostd::unique_ptr<std::shared_ptr<T>>
。我的脑袋转得飞快,我认为这是a)现在去睡觉的一个信号,b)有很好的理由不让析构函数抛出异常 :) - Daniel Frey