error:terminate called after throwing an instance of 'char'//沒有明白需要看視訊
error:terminate called after throwing an instance of 'char'
YLC_慕類2019-03-06 16:41:249018收藏3 分類專欄:C++深度剖析文章標籤:terminate()try{}catch(){} C++深度剖析專欄收錄該內容 89 篇文章4 訂閱 訂閱專欄C++解構函式異常
zhuanhttp://blog.etrnls.net/2008/06/03/cpp_destructor_exception/#more-72
C++標準中說可以假定解構函式不丟擲異常,而如果特定情況下解構函式丟擲異常將自動呼叫terminate()終止程式。
我們來看一下這條“站著說話不腰疼“的假定。首先要明確,C++的異常是和麵向物件無縫結合的,自然它要保證異常發生時區域性變數的正常銷燬。當異常丟擲的時候,有一個棧展開(stack unwinding)的過程,也就是異常丟擲點到最近的catch該異常的地方之間的所有的棧頁面被彈出,而頁面中的所有的區域性物件會被析構,可以看到,析構是和異常處理緊密結合在一起的。
現在假設在異常被啟用的情況下(比如某個地方丟擲了一個MyException)呼叫某個解構函式,而這個解構函式又丟擲了一個異常(比如叫AnotherException),那麼現在應該怎麼辦?是忽略這個新的exception繼續找能夠catch MyException的地方呢還是扔掉MyException開始找能夠處理AnotherException的地方呢?
因此C++語言擔保,當處於這一點時,會呼叫terminate()來殺死程序。所以,如果在解構函式中丟擲異常的話就不要指望誰能catch了。
如果解構函式真的可能會拋異常呢?其實這可能是不可避免的,那麼就一定要把這個異常控制在解構函式內部,千萬不能讓它跑出去,一旦跑出去後果不堪設想,很可能程式就此crash。
而我們寫程式的時候就可以像標準中說的一樣,預設析構不會產生異常。
最後看一段程式碼演示一下~
#include <iostream> #include <exception> using namespace std; class Foo { public: Foo() { cerr << "Foo ctor" << endl; } ~Foo() { cerr << "Foo dtor" << endl; throw "Bad exception!"; } void doSomething() { throw "The exception"; } }; class Bar { public: Bar() { cerr << "Bar ctor" << endl; } ~Bar() { cerr << "Bar dtor" << endl; } }; void fun1() { Foo foo; foo.doSomething(); } void fun2() { Bar bar; fun1(); } void fun3() { try { fun2(); } catch (...) { cerr << "Caught exception" << endl; } } int main() { fun3(); return 0; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
執行結果(g++ (GCC) 4.1.2 (Gentoo 4.1.2 p1.1)編譯):
Bar ctor
Foo ctor
Foo dtor
terminate called after throwing an instance of ‘char const*’
Aborted
恩,Bar的解構函式沒有呼叫而程式直接被terminate掉了。當然如果doSomething的時候沒有丟擲異常那麼這個程式是可以正常結束的,所以有時候會發現原來的程式碼跑的好好的而新加了一部分程式碼程式就崩潰了,仔細檢查新的程式碼又沒有發現什麼問題,其實原來的程式碼”好好“的執行只是假想而已……
P.S.:稍稍偏題,如果建構函式中丟擲異常,是不會呼叫解構函式的,C++認為該物件還沒真正”活“過,所以不需要”死“了,而據說Object Pascal認為既然建構函式拋異常了那這個物件已經”半活“了,所以需要呼叫解構函式讓它”死“一遍。?