C 建構函式丟擲異常會引起記憶體洩漏嗎

2021-06-19 15:43:22 字數 3825 閱讀 6851

c++ 建構函式丟擲異常會引起記憶體洩漏嗎?

我們用實際**說明問題:先看一下如下**:

#include 

using namespace std;

class inner

public:

inner()

cout<

~inner()

cout<

class outer

private:

int m_value;

inner inner1;

public:

outer(int value):m_value(value)

cout<

throw 3;

~outer()

cout<

void* operator new(size_t size)

cout<

unsigned char* tmp = ::new unsigned char[size];

return tmp;

void operator delete(void* ptr)

cout<

::delete (unsigned char*)ptr;

main()

tryouter* d = new outer(1);

catch(...)

cout<

這段**編譯後執行結果:

void* operator new(size_t size)

inner()

outer(int value)

~inner()

void* operator delete(void* ptr)

exception got it

從**執行結果來看,我們可以得出如下結論:

1. new乙個物件有兩個過程:

a.向系統申請記憶體空間  

b.在申請的記憶體空間上執行建構函式,初始化物件。

2.內部物件構造先於物件本身。

3.物件在建構函式丟擲異常後,系統會負責清理構造物件時申請的記憶體,但不會呼叫物件析構函式。

也就是說構造物件的記憶體會被釋放掉,已經完成例項化的成員物件也會成功析構。

通過valgrind工具可以看到不存在記憶體洩漏。

下面我們把**修改一下。修改只有兩處,注意紅色標記。

#include 

using namespace std;

class inner

private:

int m_value;

public:

inner()

cout<

inner(int value):m_value(value)

cout<

~inner()

cout<

class outer

private:

int m_value;

inner inner1;

public:

outer()

cout<

//throw 3;

outer(int value):m_value(value)

cout<

~outer()

cout<

void* operator new(size_t size)

cout<

unsigned char* tmp = ::new unsigned char[size];

throw 1;

return tmp;

void operator delete(void* ptr)

cout<

::delete  (unsigned char*)ptr;

main()

tryouter* d = new outer(1);

catch(...)

cout<

我們改在過載的new操作符方法中丟擲異常。

程式輸出結果:

void* operator new(size_t size)

got it

是的,這個結果想必大家已經預料到了,析構和釋放記憶體的操作都沒有執行。

valgrind 的執行結果:

發生了記憶體洩漏。

過載new操作符,使用者可以在自己的記憶體池中分配記憶體去構造物件,但是如果成功申請記憶體但後續執行丟擲異常後,就會造成記憶體洩漏。

最後修改一下**,還是在建構函式中丟擲異常,注意紅色標記

#include 

using namespace std;

class inner

private:

int m_value;

public:

inner()

m_value=1;

cout<

inner(int value):m_value(value)

cout<

~inner()

cout<

private:

int m_value;

inner inner1;

inner* inner2;

public:

outer()

cout<

outer(int value):m_value(value)

cout<

inner2 = new inner(2);

throw 1;

~outer()

cout<

void* operator new(size_t size)

cout<

unsigned char* tmp = ::new unsigned char[size];

return tmp;

void operator delete(void* ptr)

cout<

::delete  (unsigned char*)ptr;

main()

tryouter* d = new outer(1);

catch(...)

cout<

**執行結果:

void* operator new(size_t size)

inner()

outer(int value)

inner(int value)

~inner1()

void* operator delete(void* ptr)

got it

可以看到內部成員物件inner1成功析構,但是指標inner2沒有析構(因為inner2是乙個指標,清棧的時候只會呼叫棧裡的區域性物件的析構函式,但是不會delete呼叫棧裡指標),想必大家也可以預見到這樣的情況。

valgrind的輸出:4個位元組記憶體洩漏,肯定是inner2沒有成功釋放。

可以得到如下結論:

乙個物件在建構函式中丟擲異常,物件本身的記憶體會被成功釋放,但是其析構函式不會被呼叫。其內部區域性成員物件清棧時是會被釋放掉的,故其析構函式被呼叫,但是使用者在建構函式中動態生成的物件沒有被delete掉(new出來的是乙個指標,清棧時是不會delete掉棧裡的指標)。

如果乙個物件在建構函式中開啟很多系統資源,但是建構函式中後續**丟擲了異常,則這些資源將不會被釋放,建議在建構函式中加入try catch語句,對先前申請的資源進行釋放後(也就是做析構函式該做的事情)再次丟擲異常,確保記憶體和其他資源被成功**。

C 建構函式中丟擲的異常

分類 c c 程式設計 2011 04 19 10 03 4940人閱讀收藏 舉報c exception string class測試c 建構函式中丟擲的異常 1 標準c 中定義建構函式是乙個物件構建自己,分配所需資源的地 方,一旦建構函式執行完畢,則表明這個物件已經誕生了,有自己的行為和內部的執行...

C 建構函式中丟擲的異常

建構函式中丟擲的異常 1 標準c 中定義建構函式是乙個物件構建自己,分配所需資源的地 方,一旦建構函式執行完畢,則表明這個物件已經誕生了,有自己的行為和內部的執行狀態,之後還有物件的消亡過程 析構函式的執行 可誰能保證物件的構造 過程一定能成功呢?說不定系統當前的某個資源不夠,導致物件不能完全構建好...

C 建構函式 析構函式與丟擲異常

問題 建構函式可以丟擲異常麼?析構函式可以嗎?分析 從語法上來說,建構函式和析構函式都可以丟擲異常。但從邏輯上和風險控制上,建構函式可以,析構函式不推薦丟擲異常。1 建構函式可以丟擲異常 無論何時,從建構函式中丟擲異常都是可以的。動態建立物件要進行兩個操作 分配記憶體和呼叫建構函式。若在分配記憶體時...