拷貝構造函數中的陷阱


  拷貝構造函數大家都比較熟悉,通俗講就是傳入一個對象,拷貝一份副本。

  不過看似簡單的東西,實際不注意的話就會產生問題!

#include<iostream>
using namespace std;

class CExample 
{
public:
    int a,b,c;
    char *str;

public:
    //構造函數
    CExample(int tb)
    { 
        a = tb;
        b = tb+1;
        c = tb+2;
        str=(char *)malloc(sizeof(char)*10);
        strcpy(str,"123456789");
        cout<<"creat: "<<endl;
    }


    //析構函數
    ~CExample()
    {
        cout<< "delete: "<<endl;
    }

    void Show ()
    {
        cout<<a<<endl;
    }

    //拷貝構造

    //CExample(const CExample& C)
    //{
    //    str=(char *)malloc(sizeof(char)*10);
    //    strcpy(str,C.str);
    //    cout<<"copy"<<endl;
    //}
};

//全局函數,傳入的是對象
void g_Fun(CExample C)
{
    C.a=0;C.b=0;C.b=0;
    strcpy(C.str,"aaabbbccc");
    cout<<"test"<<endl;
}

int main()
{
    CExample test(1);
    cout<<"str:"<<test.str<<" a="<<test.a<<" b="<<test.b<<" c="<<test.c<<endl;
    
    g_Fun(test);//傳入對象

    cout<<"str:"<<test.str<<" a="<<test.a<<" b="<<test.b<<" c="<<test.c<<endl;
    getchar();
    return 0;
}

這個結果似乎出乎了我們的預料,作為形式參數 test對象被修改了,同時是test.str的部分被修改了,test的整數成員變量沒有被修改!

咱們先了解一下系統默認的拷貝構造函數,因為類中沒有寫自己的拷貝構造函數,所以調用的是默認的拷貝構造函數。

Thinking in c++:對於簡單結構,編譯器會自動生成一個缺省的,就是位拷貝(bitcopy)。
對於比較復雜的類型,編譯器就會自動生成一個缺省的拷貝構造函數。

class CExample 
{
    int a,b,c;
};

這就是一個簡單結構的類,位拷貝,就是按對象在內存中的二進制進行拷貝,對於不涉及指針等類型的時候,位拷貝是比較不錯的拷貝方法。

但是,要是一個類中有指針類型的時候,如

class CExample 
{
    int a,b,c;
    char *str;
};

位拷貝就會把指針地址拷貝了一下,話句話說,這里只進行了“淺拷貝”,一旦副本里涉及到指針的操作,必然就會影響到原始對象的成員變量,這就是導致,上面代碼中對象的整數變量沒被修改(對整數變量的位拷貝其實就是一種“深拷貝”),而str所指的對象被修改的原因。

那么該如何防止對副本的修改影響原始對象呢?

答案是用戶自定義拷貝構造函數!

    CExample(const CExample& C)
    {
        a=C.a;b=C.b;c=C.b;
        str=(char *)malloc(sizeof(char)*10);
        strcpy(str,C.str);
        cout<<"copy"<<endl;
    }

 

這樣就可以正確完成拷貝構造的操作了。

總結:對於簡單的數據類型,可以使用系統默認的拷貝構造函數;但對於復雜的數據類型(如指針),其實就是深拷貝和淺拷貝的區別!一般類如果包含指針或引用成員,應該遵守Rule of Three原則。(感謝@24K純開源

 

@24K純開源 指出的三法則:

三法則英語rule of threethe Law of The Big ThreeThe Big Three三法則三大定律)在 C++ 程序設計里,它是一個以設計的基本原則而制定的定律,三法則的要求在於,假如類型有明顯地定義下列其中一個成員函數,那么程序員必須連其他二個成員函數也一同編寫至類型內,亦即下列三個成員函數缺一不可。 [1]:

參考 http://zh.wikipedia.org/wiki/%E4%B8%89%E6%B3%95%E5%89%87_(C%2B%2B%E7%A8%8B%E5%BC%8F%E8%A8%AD%E8%A8%88)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM