2012-08-23 130 views
5

複製構造函數用於很多事情,例如當我需要使用指針或爲對象動態分配內存時。但看這個例子在tutorialpoint.com解釋複製構造函數示例

#include <iostream> 

using namespace std; 

class Line 
{ 
public: 
    int getLength(void); 
    Line(int len);    // simple constructor 
    Line(const Line &obj); // copy constructor 
    ~Line();      // destructor 

private: 
    int *ptr; 
}; 

// Member functions definitions including constructor 
Line::Line(int len) 
{ 
cout << "Normal constructor allocating ptr" << endl; 
// allocate memory for the pointer; 
ptr = new int; 
*ptr = len; 
} 

Line::Line(const Line &obj) 
{ 
cout << "Copy constructor allocating ptr." << endl; 
ptr = new int; 
*ptr = *obj.ptr; // copy the value 
} 

Line::~Line(void) 
{ 
cout << "Freeing memory!" << endl; 
delete ptr; 
} 
int Line::getLength(void) 
{ 
return *ptr; 
} 

void display(Line obj) 
{ 
    cout << "Length of line : " << obj.getLength() <<endl; 
} 

// Main function for the program 
int main() 
{ 
    Line line(10); 

    display(line); 

    return 0; 
} 

結果是:

Normal constructor allocating ptr 
Copy constructor allocating ptr. 
Length of line : 10 
Freeing memory! 
Freeing memory! 

,當我註釋掉(拷貝構造函數)和內析構函數的代碼中,我得到了相同的結果:

Normal constructor allocating ptr 
Length of line : 10 

那麼在這裏使用複製構造函數還是不同?另外爲什麼「釋放記憶!」發生兩次?

+2

看看結果。在第一個例子中,你將分配兩個不同的整數並釋放它們。第二,你分配一個並釋放它兩次。不好。 – chris

+0

它沒有在第二個例子中釋放,我只是忘記評論「cout <<」釋放內存!「在構造函數中的語句,所以它實際上並沒有釋放 – Omar

+0

然後你已經分配了一些你還沒有釋放的東西,如果它開始變得比創建一個和結束程序更復雜,就是內存泄漏 – chris

回答

3

display()函數的參數是按值傳遞的,因此編譯器會調用複製構造函數來創建它。當類定義它的拷貝構造函數時,你會得到正確的語義:拷貝構造函數生成一個拷貝,並且拷貝有自己的內存來保存長度。當您刪除複製構造函數時,編譯器會爲您生成一個,並且傳遞到display()的副本與原始指針具有相同的指針。當該副本被破壞時,它將刪除ptr指向的內存。當原始數據被破壞時,它會再次刪除相同的內存(這裏恰好沒有可見的效果)。這絕對不是你想要發生的,這就是爲什麼你需要定義一個拷貝構造函數。正如@Joe所說:在析構函數中,打印'ptr'的值可以更清楚地看到它。

4

打印正在釋放的內存地址。

我相信你會發現編譯器爲你生成構造函數,做了一個包含指針的內容的值副本,並且你正在雙向釋放指針並且幸運的是運行時並沒有抱怨它。

編譯器生成的拷貝構造函數仍然被調用 - 在這方面什麼也沒有改變,因爲你沒有編寫它,你只是不打印任何東西。

0

形式

T (const & T); 

單個參數必須是常量引用相同類型 的現有對象的某些類型T的構造函數創建中使用的現有對象 的副本每當的副本需要對象 包含函數參數,函數返回結果 C++中基於指針的數組的問題: - 沒有範圍檢查。 無法與== 進行有意義的比較沒有數組賦值(數組名稱是常量指針)。 如果將數組傳遞給函數,則必須將大小作爲單獨的參數傳遞。

1

如果我們沒有定義我們自己的拷貝構造函數,C++編譯器會爲每個類創建一個默認拷貝構造函數,從而在對象之間進行成員智能拷貝。編譯器創建的複製構造函數一般工作正常。我們需要定義我們自己的拷貝構造函數,只有當一個對象有指針或者像文件句柄,網絡連接這樣的資源的任何運行時分配時。