2014-07-25 38 views
1

我有以下代碼中的函數調用動態分配一個類對象:爲什麼分配給非基準的基準會改變其動態行爲

#include <iostream> 

class A 
{ 
    public: 
     A(){std::cout<<"Constructing..."<<std::endl;} 
     ~A(){std::cout<<"Deconstructing..."<<std::endl;} 
}; 

A & f() 
{ 
    std::cout<<"Calling f()"<<std::endl; 
    A * pa = new A(); 
    std::cout<<"End calling f()"<<std::endl; 
    return *pa; 
} 

int main() 
{ 
    A & b = f(); 
} 

輸出是:

Calling f() 
Constructing... 
End calling f() 

這意味着類對象從不刪除。

但是,如果我在main行更改爲:

A b = f(); 

的輸出是:

Calling f() 
Constructing... 
End calling f() 
Deconstructing... 

這意味着類對象被自動刪除。

爲什麼分配對非引用的引用會改變其動態行爲?

+0

只有'b'在第二個被破壞,而不是'* pa'。 C++具有價值語義。引用是例外。 – chris

+0

@chris如果在第二種情況下從'* pa'複製了'b',爲什麼沒有在這裏調用的構造函數? –

+2

@HaliangZhang:因爲它被複制(或移動),使用複製(或移動)構造函數。你只從默認的構造函數中打印,這裏沒有使用它。 –

回答

4

對由new創建的動態對象沒有任何更改。這兩種情況都沒有被破壞,因爲只有明確使用delete才能銷燬。

在第二種情況下,通過複製動態對象來創建第二個對象b。是自動的,當它超出範圍時會被破壞,所以你會看到一條Deconstructing...消息。

由於它是由複製構造函數初始化的,而不是默認構造函數,因此您看不到相應的Constructing...消息。你可以添加一個拷貝構造函數看到:

A(A const &){std::cout<<"Copying..."<<std::endl;} 

給輸出

Calling f() 
Constructing... 
End calling f() 
Copying... 
Deconstructing... 

在一般情況下,總是使用智能指針和其他RAII類型來管理動態資源,以避免內存泄漏和其他壽命混亂問題。

1

當你聲明一個值類型時,它被構造在堆棧上,當編譯器超出作用域時,編譯器負責調用它的析構函數。但是,通過調用new在堆上創建實例時,編譯器無法知道何時不再需要該實例,因此,編程人員可以使用delete間接調用其析構函數。事實上,你對堆上的對象有一個引用,這並不能讓編譯器知道什麼時候該對象被銷燬。

2

A & b = f(); 

b的情況下指的是在堆上創建的對象。

A b = f(); 

b的情況下創建數據的在堆上的副本(可以移動)。這個函數在函數退出時被破壞(當b超出範圍時)。

在這兩種情況下,堆中的對象都是單獨存在的。

爲了進一步探索,複製構造函數的添加將有助於A(A const&),然後打印一條消息,甚至使其成爲private,並注意編譯錯誤有助於標記副本及其位置。

注意:當你在一個函數中有一個對象然後不要銷燬它,或者不要將指針移動到某個其他所有者時,你會泄漏內存。贊成庫管理工具如unique_ptrshare_ptr來管理資源(RAII)。