2011-10-20 57 views
2

我在執行深度複製時想克隆對象指針時出現問題。 就像我有T * t1,並且我想以* t1.x = * t2.x的方式創建一個新的對象指針T * t2。複製構造函數中的指針參數

它是一個好主意,寫一個拷貝構造函數會像:

T(const T* cpy) 
{ 
    m_var = (*cpy).m_var; 
} 

T* t1 = new T; 
T* t2(t1); 

什麼事情,我應該照顧,如果採用上述辦法的?

感謝 魯奇

回答

4

要做到這一點,你應該寫一個正常的拷貝構造和使用它像這樣:

T(const T& cpy) 
: m_var(cpy.m_var) // prefer initialization-list, thanks to @Loki Astari 
{} 

T* t1 = new T; 
T* t2 = new T(*t1); 

在你展示的代碼,T* t2(t1);絕不會叫你聲明的構造(順便說一下,它不是一個複製構造函數),因爲它只是簡單地將指針t2初始化爲指針t1的值,從而使兩個指向同一個對象。

正如@Nawaz所說,這個拷貝構造函數等同於編譯器生成的拷貝構造函數,所以你實際上並不需要編寫它。實際上,除非你有任何手動管理的資源(通常你不應該這麼做),否則編譯器生成的複製構造函數一定會很好。

+1

他不需要寫*正常的複製構造函數*。編譯器生成一個就足夠了。 – Nawaz

1

拷貝構造函數的定義需要一個參考,因此:

T(T const& copy)   // This defines a copy constructor. 
    : m_var(copy.m_var)  // Prefer to use the initializer list. 
{} 

所以你需要傳遞一個參考。
如果要複製一個指針的使用則是:

T* t2 = new T(*t1); 
0

這不會做你認爲:

T* t2(t1); 

,因爲你只聲明一個指針,而不是對象。指針初始化爲另一個指針的值。它應該是:

T* t2 = new T (t1); 

創建一個新的對象。

至於副本,你目前正在做一個淺拷貝,因爲你只是複製指針值,而不是指針指向的數據。當原始副本或副本被銷燬時,執行淺拷貝會導致問題 - 如果刪除m_var,則另一個對象具有指向刪除內存的指針,如果取消引用,則調用未定義行爲TM。深拷貝修復了這個:

T(const T* cpy) 
{ 
    m_var = new VarType (cpy->m_var); // VarType being whatever m_var is 
} 

這就是現在需要的m_var的類型,這也必須是深,以防止上述缺失問題的拷貝構造函數。

深度複製數據的缺點是增加了內存需求並花費大量時間分配內存並複製數據。這可以使用引用計數對象來解決。這些都有幾種口味,智能指針是最常見的。這裏,相同的底層對象是父對象的所有副本的引用。當父對象被刪除時,對象的智能指針的析構函數只有在刪除了對它的所有引用時纔會銷燬該對象。

智能指針的缺點在於,從一個擁有對象中更改數據會修改所有擁有對象將看到的數據。爲了獲得兩全其美的效果,你希望有一個'修改'系統的副本。這隻會在底層數據被擁有對象修改時增加內存使用。