2016-06-15 11 views
6

Ich lerne, wie bedingte noexcept zu verwenden und auf dieses Problem stoßen. Angenommen, ich habe eine Klasse:noexcept Ausdruck vs Typ Merkmale

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

private: 
    T value_; 
}; 

Für den /* ??? */ Teil, ich dachte, dass wir entweder noexcept(T(std::move(value))) oder std::is_nothrow_move_constructible<T>::value verwenden können, bis ich auf this stolperte.

Also, wenn ich noexcept(noexcept(T(std::move(value)))) verwenden, streng genommen Ich sage, dass „dieser Konstruktor ist noexcept iff Bau und zerstörenden ein T ist noexcept“?

Obwohl Destruktoren, die werfen, sollten in Brand gesteckt und verbrannt werden.

+3

Können Sie umgehen dies mit z. 'noexcept (neues T (std :: move (value)))' oder etwas? Da es sich um einen unausgewerteten Ausdruck handelt, wird nicht wirklich etwas zugewiesen, sondern es sollte speziell "undicht" sein und so sollte der dtor nicht beteiligt sein ... Ich schätze, du musst vielleicht eine neue Version von new verwenden, da du t wollen 'std :: bad_alloc' erkennen. –

Antwort

6

Gute Frage, siehe auch this language defect discussion. Aus seinem Namen geht hervor, dass std::is_nothrow_move_constructible<T>::value nur auf die Konstruierbarkeit aus einem rvalue beziehen sollte (aber in der Praxis auch auf die Zerstörung beziehen kann), während sich noexcept(T(std::move(value))) immer sowohl auf die Konstruktion als auch auf die Zerstörung bezieht.

in Ihrem Fall also, die meisten zu sparen Art und Weise, die ungelöste Frage der std::is_nothrow_move_constructible Züge zu vermeiden, ist die Platzierung neu zu bedienen, mit std::bad_alloc das Problem zu vermeiden (in Chris Beck Kommentar erwähnt), und in ähnlicher Weise verwenden T ' s Destruktor für den Destruktor des Wrappers.

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_; 
}; 
+1

_ "es ist klar, dass' std :: is_nothrow_move_constructible :: value "sollte nur auf den Konstruktor" _ beziehen - das ist überhaupt nicht klar, das Problem ist ungelöst, und es ist sicherlich nicht wahr, dass es einen klaren Konsens gibt, dass die die Erwartungen des Einsenders sind richtig oder es liegt ein Fehler im Standard vor. –

+0

@ JonathanWakely Punkt genommen. Ich habe die Frage bearbeitet. Ich würde denken, dass ein C++ - Standard-Konstrukt tun sollte, was es auf der Zunge sagt, d. H. Testet in diesem Fall nur, ob ein Typ einen Konstruktor für die Konstruktion ohne "No Throw" hat, aber sonst nichts. – Walter

+0

Aber das Merkmal ist nicht "has nothrow move constructor" (siehe [N3142] (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3142.html) für warum es nicht ist Das ist). Stattdessen sagt es Ihnen, ob das Erstellen eines Objekts aus einem Rvalue werfen kann, was nicht das Gleiche ist. Und in den meisten Fällen, in denen Sie wissen wollen, ob das Erstellen von Würfen sinnvoll ist, möchten Sie auch wissen, ob das Zerstören von Würfen möglich ist, weil es nicht gut ist, die Elemente eines Containers so zu optimieren, dass deren Destruktoren werfen können. –