Почему деструкторы интеллектуальных указателей типа std не наследуют статус noexcept dtor указанного объекта
В 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, такого как noexcept(std::is_nothrow_destructible<T>::value)
на декларации деструктора умного указателя.
Однако в стандарте об этом ничего не говорится, а код стандартной библиотеки, на который я смотрел, этого не делает.
Кто-нибудь знает, почему стандартные умные указатели не передают деструктор умного указателя не исключая статус деструктора инстанцирующего типа?
1 ответ
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
POV.
За std::unique_ptr
, есть
20.7.1.2.2 деструктор unique_ptr [unique.ptr.single.dtor]
1
~unique_ptr();
Требуется: выражение
get_deleter()(get())
должен быть правильно сформирован, иметь четко определенное поведение и не создавать исключений. [ Примечание: использованиеdefault_delete
требуетT
быть полным типом. - примечание]
Это означает, что удалитель должен убедиться, что он не выбрасывает, что не обязательно зависит от деструктора T
при использовании null-delete.