2013-03-11 22 views
1

我指着下面的文章:使用相同的變量將值構造函數調用函數複製兩次會導致問題?

http://www.codeproject.com/Tips/78946/C-Copy-Constructor-in-depth

,我們有代碼:

class string 
{ 
    // constructor 
    string(char* aStr) 
    { 
     str = new char[sizeof(aStr)]; 
     strcpy (str,aStr); 
    } 

    // destructor 
    ~string() 
    { 
     del str; 
    } 

    char *getChars(){ return str; } 
    char* str; 
}; 


void function (string str) 
{ 
    // do something 
} 


void main() 
{ 
    string str("hello"); 
    function(str); 
    function(str); // program crashes 
} 

我不明白,爲什麼在main,就與第二次調用問題function?當str傳遞給第一個電話時,這隻會是str的副本,因此function內的str的任何操作都不會影響main中聲明的變量str

+3

[Rule of Three](http://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming));它只會在一次通話中崩潰。 – 2013-03-11 21:50:52

+2

[三條法則是什麼?]的可能重複(http://stackoverflow.com/questions/4172722/what-is-the-rule-of-reeree) – juanchopanza 2013-03-11 21:51:39

+2

三條規則似乎是今晚的熱門主題。 – juanchopanza 2013-03-11 21:52:02

回答

3

默認的拷貝構造函數會對對象進行逐位拷貝。換句話說,指針成員被複制,但不是它指向的對象。如果使用默認構造函數並僅執行淺拷貝,則兩個對象中的指針都將指向相同對象

具體到你的問題:

第一次調用function(str)一切工作正常,當函數結束時,堆棧上的輸入參數被破壞(這是str副本,但使用的是默認複製構造函數的指針指向與原始對象相同的位置),並且其析構函數將被稱爲刪除指針指向的對象。

第二次調用function(str),當函數結束時,析構函數將立即嘗試釋放str中指針指向的地址並崩潰。

爲了避免這樣的問題,你應該定義你自己的拷貝構造函數,它不僅適當地複製對象的指針,還可以執行深度拷貝。

2

問題是string類中的str成員是一個指針。這意味着當創建字符串的副本時,該指針的值被複制,但指針的值只是一個內存位置。所以當你調用function(str)時,即使它沒有修改指針的值,它也會修改該位置的內存。

1

默認情況下,C++只知道如何用默認的拷貝構造函數做一個淺度數據拷貝。所以,是的,第一個撥打function的電話確實製作了str的「副本」,但是這個副本並不是一個副本,因爲被複制的是char*字符串類的實例數據。也就是說,C++只是複製一個地址,但不夠智能,不能爲新字符串分配空間並複製內容。你必須用自定義拷貝構造函數自己做。

0

str的構造函數沒有爲後續調用strcpy分配足夠的字節。之後,所有投注都關閉。一旦解決了,寫一個合適的拷貝構造函數和拷貝賦值操作符。