網上比較經典的總結:
什麼函式都有可能失敗,建構函式也不另外,比如new乙個物件或空間不成功。當建構函式失敗的時候,其實很多時候我們不想這個物件被繼續生成,這個時候就可以在建構函式裡面丟擲異常。c++規定建構函式丟擲異常之後,物件將不被建立,析構函式也不會被執行,但已經建立成功的部分(比如乙個類成員變數)會被部分逆序析構,不會產生記憶體洩漏。但有些資源需要在丟擲異常前自己清理掉,比如開啟成功的乙個檔案,最好關閉掉再丟擲異常(雖然系統也會把這個資源**),因為丟擲異常之後析構函式不會被執行了。
(1) c++中通知物件構造失敗的唯一方法那就是在建構函式中丟擲異常;(這句話並不是說我們只有這個方法才能讓上層知道建構函式失敗,雖然建構函式沒有返回值,我們完全可以在建構函式中傳入乙個引用值,然後在裡面設定狀態,執行完建構函式之後任然可以知道是否失敗,但這種情況下面物件其實還是被構造出來的,只是裡面有資源分配失敗而已,並且析構函式還是會執行。這和我們構造失敗不生成物件的初衷不符。)
(2) 建構函式中丟擲異常將導致物件的析構函式不被執行;(但已經生產的部分成員變數還是會被逆向析構的)
(3) 當物件發生部分構造時,已經構造完畢的子物件將會逆序地被析構;
網上的乙個栗子:
乙個例項物件的構造:
第一步,分配足夠的記憶體,如果失敗就是棧溢位或丟擲std::bad_alloc的異常,所以在這步你不用擔心記憶體洩露,而且這一步你是不能插手的,如果這步成功,就進入第二步。
new運算子的實現保證了記憶體洩漏不會發生。例如
t *p = new t;
將被編譯器轉換給類似下面的樣子:(其實和我們自己釋放已經申請的資源的思想流程是一樣的)
//第一步,分配原始記憶體,若失敗則丟擲bad_alloc異常
trycatch(...)
第二步,呼叫建構函式,在通常情況下,如果建構函式為空或沒有進行動態記憶體分配,你就不用關心記憶體洩露了
你需要關心的是建構函式中有動態記憶體分配
classa
catch(bad_alloc)~a()
;intmain()
a*pa=null;trycatch(bad_alloc){
cout<
delete pa;return 0;
pa是用null初始化的,即使在給a分配記憶體時(第一步)失敗,也不會導致後面的delete pa出錯。
對於建構函式可能失敗的做法一般有兩種
1. 在建構函式中丟擲異常,本物件構造未完成,它的析構函式不會被呼叫。當然,我們有義務釋放已經分配到的資源。簡單,最常見。
2. 把資源的初始化工作放在另乙個單獨函式中,比如 bool init(...),由物件建立者(比如工廠方法)先呼叫建構函式,再呼叫init方法。atl中常見。
建構函式裡丟擲異常 c 可否同時丟擲兩個異常
c 可否同時丟擲兩個異常 wcy123.github.io在 c 中,如果我們丟擲異常後 在捕獲異常之前,會析構掉所有還在堆疊上的物件。include using namespace std class object object object void foo catch const except...
建構函式中丟擲的異常
建構函式中丟擲的異常 1 標準c 中定義建構函式是乙個物件構建自己,分配所需資源的地方,一旦建構函式執行完畢,則表明這個物件已經誕生了,有自己的行為和內部的執行狀態,之後還有物件的消亡過程 析構函式的執行 可誰能保證物件的構造過程一定能成功呢?說不定系統當前的某個資源不夠,導致物件不能完全構建好自己...
建構函式中丟擲的異常
標準c 中定義建構函式是乙個物件構建自己,分配所需資源的地方,一旦建構函式執行完畢,則表明這個物件已經誕生了,有自己的行為和內部的執行狀態,之後還有物件的消亡過程 析構函式的執行 可誰能保證物件的構造過程一定能成功呢?說不定系統當前的某個資源不夠,導致物件不能完全構建好自己。物件總是由不斷的繼承或不...