2016-06-13 7 views
9

Sehen Sie sich diesen Code an, der dazu führt, dass das Programm beendet wird, ohne dass die Ausnahme abgefangen wird.Warum Ausnahmen von unique_ptr destructor das Programm beendet?

#include <iostream> 
#include <string> 
#include <memory> 
#include <stdexcept> 
using namespace std; 

struct test { 
    ~test() noexcept(false) { 
    throw runtime_error("-my-cool-exception-"); 
    } 
}; 

int main() 
{ 
    try { 
    auto ptr = unique_ptr<test>(new test()); 
    //test t; // this is ok, without unique_ptr<test> it works fine. 
    } 
    catch(exception& e) { 
    cout << "this is not called, the program is aborted"; 
    cout << e.what() << endl; 
    } 
    return 0; 
} 

Diese Frage unterscheidet sich von Stapelüberlauf Frage: throwing exceptions out of destructor.

Der Unterschied ist, dass nur wenn ich unique_ptr<test> die Ausnahme nicht gefangen wird.

Sie können die Live-Code, bearbeiten und sehen hier http://cpp.sh/9sk5m

+6

Da 20.10.1.2.2 erfordert, dass das Löschen keine Ausnahmen auslöst. Sie verletzen die Bibliotheksvoraussetzungen. –

+0

Ich habe eine Bibliothek, die völlig davon abhängt, kann es nicht brechen. Gibt es einen Workaround dafür? Vielen Dank. – amin

+9

Problemumgehung: Repariere deine Bibliothek, tu es jetzt bevor [es beißt dich weiter] (http://stackoverflow.com/a/130123/3426025). – BeyelerStudios

Antwort

13

kompilieren, die von der Norm gefordert wird. Wie pro unique.ptr.single.dtor, 20.10.1.2.2.1:

Voraussetzung: Der Ausdruck get_deleter() (get()) müssen gut ausgebildet sein, so gut definierte Verhalten haben, und werden keine Ausnahmen werfen. [Hinweis: Die Verwendung von default_delete erfordert, dass T ein vollständiger Typ ist. - Endnote]

(Hervorhebung von mir)

Also wirklich, es spielt keine Rolle, ob Sie sich destructor hat noexcept(false) oder nicht. Es ist verboten, in diesem Fall das letzte Wort zu werfen.

Dies ist im Allgemeinen der Fall std:: - sofern nicht anders angegeben. Wie pro res.on.functions, 17.6.4.8.2.4:

Insbesondere werden die Effekte in den folgenden Fällen nicht definiert: [...] , wenn eine Ersatzfunktion oder Handler-Funktion oder destructor Betrieb über eine Ausnahme beendet wird, sofern dies nicht ausdrücklich in der erlaubt anwendbares erforderliches Verhalten: Absatz.

(Hervorhebung von mir)

Hinweis: Im Allgemeinen Sie können haben werfen Destruktoren mit noexcept(false). Dies ist jedoch sehr gefährlich, da std::terminate aufgerufen wird, wenn der Stapel aufgrund einer geworfenen Ausnahme abgewickelt wurde. Wie pro except.ctor, 15.2.1:

Als Die Steuerung geht von dem Punkt, wo eine Ausnahme von einer Behandlungsroutine ausgelöst wird, Destruktoren werden durch ein Verfahren aufgerufen wird, die in diesem Abschnitt angegeben, Stapel Abwickeln genannt. Wenn ein Destruktor, der direkt durch das Abwickeln des Stacks aufgerufen wird, mit einer Ausnahme beendet wird, wird std :: terminate aufgerufen ([except.terminate]). [Hinweis: Destruktoren sollten daher normalerweise Ausnahmen abfangen und sie nicht aus dem Destruktor ausbreiten lassen. - Endnote]

(Hervorhebung von mir)

See it live on Coliru.

+1

Es sollte angemerkt werden, dass, selbst wenn Sie * Ihren * Destruktor 'noexcept (false)' angeben, dies die Tatsache nicht ändert, dass 'destructor von 'unique_ptr' 'noexcept' bleibt. So wird die Ausnahme dort verschluckt. –

+0

"geschluckt" bedeutet, dass es verschwindet. Es tut es nicht. – Ven

+0

OK, "explode" ist wahrscheinlich ein genauerer Ausdruck als "swallow";) Aber so oder so wirst du nicht sehen, dass diese Ausnahme deine 'catch' Aussage erreicht, egal wie sehr du' noexcept (false) 'nimmst . –