Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

noexcept expression vs type traits

Tags:

c++

c++11

I'm learning how to use conditional noexcept and come across this problem. Suppose I have a class:

template<typename T>
class Wrapper {
public:
    Wrapper(T&& value) noexcept(/* ??? */)
        : value_(std::move(value))
    {}

private:
    T value_;
};

For the /* ??? */ part, I thought we can use either noexcept(T(std::move(value))) or std::is_nothrow_move_constructible<T>::value, until I stumbled upon this.

So if I use noexcept(noexcept(T(std::move(value)))), strictly speaking I'm saying that "this constructor is noexcept iff constructing and destructing a T is noexcept"?

Although destructors that throw should be put on fire and burned.

like image 270
Zizheng Tai Avatar asked Jun 15 '16 21:06

Zizheng Tai


1 Answers

Good question, see also this language defect discussion. From its name it appears clear that std::is_nothrow_move_constructible<T>::value should only relate to the constructibiliry from an rvalue (but in practice may also relate to the destruction), while noexcept(T(std::move(value))) always relates to both construction and destruction.

So, in your case, the most save way, avoiding the unresolved issue of the std::is_nothrow_move_constructible traits, is to use placement new, avoiding the issue with std::bad_alloc (mentioned in Chris Beck's comment), and, similarly, use T's desctructor for the wrapper's destructor.

template<typename T>
class Wrapper {
public:
    Wrapper(T&& value) noexcept(new(nullptr) T(std::move(value)))
        : value_(std::move(value))
    {}
    ~Wrapper() noexcept(noexcept(value_.T::~T()))
    {}
private:
    T value_;
};
like image 71
Walter Avatar answered Oct 16 '22 16:10

Walter