2012-10-21 30 views
2

代碼:
C++非完全構造對象解除分配

#include<iostream> 
using namespace std; 
class A{ 
    public: 
    A(){cout << "A() Constructor " << endl; 
     throw 1; 
    } 

}; 


int main(){ 
A* p=0; 
cout << p << endl; // p value is 0 
try{ 
p=new A(); // object is not fully constructed, no address is returned to p. for future deallocation 

} 
catch(...){cout << "Exception" << endl;} 
cout << p << endl; // this will output that p has the value 0,proof that no address was returned to p. 


} 

存儲器被分配用於在堆中的目的,存儲器的地址被傳遞到構造 但當構造throw 1;然後的對象類型A不會被認爲是完全構建的對象。所以沒有 指針會返回指針p。隨時糾正我,如果我瞭解錯誤的東西。

問題:
1)所以我的問題是如何在這種情況下可能釋放內存的目的。我不是在談論 析構函數調用,但內存釋放。

2)當我在main函數內部創建類型爲A的本地對象時,該怎麼辦。顯然它也不會被完全構建。何時該對象被釋放(在調用完全構造的子對象的析構函數之後)。

+0

你不能刪除它,因爲p是空指針,並且對象A被分配到的內存地址沒有被傳遞給這個指針,因爲在構造函數中拋出了異常 – AlexDan

+1

正確的方法做它就叫做共享指針。 – Florian

回答

4

通過new A()完成的分配由多個步驟組成:

  1. 使用operator new(sizeof(A))分配內存。
  2. 嘗試在分配的內存中默認構造一個對象。
  3. 當默認構造失敗時,operator delete(x)被調用時使用前面獲得的地址。

更一般地,如果使用一個重載operator new(),例如new(allocator) A()它調用operator new(size_t, Alloctor)(其中allocator可轉化爲Allocator),一個對應的operator delete()被調用。

作爲異常拋出的一部分,所有部分構造的子對象也被銷燬(按照它們構造的相反順序)。也就是說,如果從對象的構造函數中拋出異常,則不需要關心清理(假設所有子對象都正確地管理它們分配的資源)。這是真實的,不管對象是分配在堆還是堆上。

+0

如果我的類中有「A * p」,並且我使用p = new A()初始化了這個指針,那該怎麼辦?我正要從~A()析構函數中釋放這個內存。所以由於A()構造函數拋出一個異常,它阻止了它的析構函數被調用,所以我不能釋放p指向的內存。在這種情況下我應該怎麼做? – AlexDan

5

1)取消分配是爲你完成的。

2)如果它是一個本地對象,它永遠不會被分配到第一個地方。

+0

本地對象,爲什麼它不會得到分配的第一個地方。從我知道的地方對象得到分配時,當執行流程進入它們存在的範圍之後,構造函數在該內存中被調用。所以當執行進入範圍時它們已經被分配了。那麼他們怎麼可能不會被分配呢? – AlexDan

+0

我可以同意你關於對象的存在。如果構造函數失敗,該對象將永遠不存在,但這並不意味着它不會被分配(在內存中)。這對於本地和動態對象都是一樣的。如果我瞭解錯誤,請隨時糾正我。 – AlexDan

+0

對於我來說,分配意味着使用new或malloc進行堆分配。顯然,本地對象必須放置在內存中,但這種情況如何發生並不是你可以控制的,所以它不是你需要擔心的。它只是發生,它只是工作。 – john

5

當一個構造函數拋出爲該對象分配的內存被自動釋放時,順便說一句析構函數沒有被調用。你不需要釋放。

+0

是的我知道析構函數不會被調用,因爲對象沒有完全構造。我可以理解,在這兩種情況下都會釋放內存,對於局部對象和動態分配的構造函數拋出異常之後會自動分配一個內存? – AlexDan

+0

是的。不管對象是如何構造的,如果構造函數拋出的內存將被自動釋放。 –

1

在CPP,構造(構造函數)調用的序列是:

  • 虛基類:虛擬基礎構造函數,根據深度優先順序調用。
  • 基類:根據定義類中的派生聲明的基類調用序列。
  • 非靜態成員對象
  • 派生類ctor;

析構函數(dtor)按相反順序調用。

CPP確保完全構建的對象(Not Pointers)的資源將被釋放。

有RAII(資源獲取初始化)。我們使用對象來包裝原始指針來分配內存,然後在dtor中釋放內存。如果派生對象由於(沒有足夠的內存,異常等)而部分構造,則會調用成員對象dtor。

在上面的簡單例子中,沒有分配資源,所以沒有資源泄漏。

但是如果在拋出之前有成員指針分配內存,就會出現內存泄漏。如果我們將內存包裝在一個類中,並將這個類的一個對象作爲一個組件(使用RAII),那麼就不會有內存泄漏。