c++ 副本構造器


我們都知道兩個指針指向同一個變量時如果一個指針被釋放那么另一個就會出問題

為了說明問題我做了一個很惡心的小例子

class C
{
public :
    C(int v)
    {
        ptrInt=new int;
        *ptrInt=v;

        valueInt = v;
    }

    ~C()
    {

    }
    void DelIntV()
    {
        valueInt=0;
        delete ptrInt;
    }
    
    C(const C& c)
    {

    }
    int * ptrInt;
    int valueInt;
private:
    
};


int main()
{
    C c1(2);
    C c2(3);
    c2=c1;
    std::cout<<"ptrInt "<<c2.ptrInt<<"  value "<<*c2.ptrInt<<std::endl;
    std::cout<<"valueInt "<<c2.valueInt<<std::endl;
    c1.DelIntV();

    std::cout<<"address  "<<c2.ptrInt<<"  value "<<*c2.ptrInt<<std::endl;
    std::cout<<"valueInt "<<c2.valueInt<<std::endl;
    std::cin.get();
    return 0;
}

 

 

這是把c1賦值給了c2后把指針ptrInt的值輸出和valueInt輸出,再把c1的指針給delete,valueInt賦值為0

再輸出c2的ptrInt和valueInt就會發現指針有問題,看一下輸出結果:

已經不對了吧。

為了解決這樣的問題我第一個想到的就是重載操作符=

C& operator=(const C &c)
    {
        if(this!=&c)
        {
            delete ptrInt;
            ptrInt = new int;
            *ptrInt= *c.ptrInt;
            valueInt=c.valueInt;
        }
        return *this;
    }

完整代碼

class C
{
public :
    C(int v)
    {
        ptrInt=new int;
        *ptrInt=v;

        valueInt = v;
    }

    ~C()
    {

    }
    void DelIntV()
    {
        valueInt=0;
        delete ptrInt;
    }
    
    C(const C& c)
    {

    }
    int * ptrInt;
    int valueInt;

    C& operator=(const C &c)
    {
        if(this!=&c)
        {
            delete ptrInt;
            ptrInt = new int;
            *ptrInt= *c.ptrInt;
            valueInt=c.valueInt;
        }
        return *this;
    }
private:
    
};


int main()
{
    C c1(2);
    C c2(3);
    c2=c1;
    std::cout<<"ptrInt "<<c2.ptrInt<<"  value "<<*c2.ptrInt<<std::endl;
    std::cout<<"valueInt "<<c2.valueInt<<std::endl;
    c1.DelIntV();

    std::cout<<"address  "<<c2.ptrInt<<"  value "<<*c2.ptrInt<<std::endl;
    std::cout<<"valueInt "<<c2.valueInt<<std::endl;
    std::cin.get();
    return 0;
}

再看一下輸出結果:

這下就正確了吧,但是如果 我們在main函數里做一個修改

int main()
{
    C c1(2);
    C c2=c1;//這里直接賦值
    std::cout<<"ptrInt "<<c2.ptrInt<<"  value "<<*c2.ptrInt<<std::endl;
    std::cout<<"valueInt "<<c2.valueInt<<std::endl;
    c1.DelIntV();

    std::cout<<"address  "<<c2.ptrInt<<"  value "<<*c2.ptrInt<<std::endl;
    std::cout<<"valueInt "<<c2.valueInt<<std::endl;
    std::cin.get();
    return 0;
}

這樣后錯誤就又和之前一樣了,為什么呢,

編譯器將在c類里找一個副本構造器(copy constructor)如果找不到它會自己創建一個,

即使我們對操作符=進行了重載也沒有用,由編譯器自己創建的副本構造器仍會以"逐們復制"

的方式把c1賦值給c2

這樣我們還要重新實現這個副本構造器,

className(const className &cn);

我是這樣做的

    C(const C& c)
    {
        *this=c;
    }

這里的=其實就是調用的重載的=方法

完整代碼

class C
{
public :
    C(int v)
    {
        ptrInt=new int;
        *ptrInt=v;

        valueInt = v;
    }

    ~C()
    {

    }
    void DelIntV()
    {
        valueInt=0;
        delete ptrInt;
    }
    
    C(const C& c)
    {
        *this=c;
    }
    int * ptrInt;
    int valueInt;

    C& operator=(const C &c)
    {
        if(this!=&c)
        {
            delete ptrInt;
            ptrInt = new int;
            *ptrInt= *c.ptrInt;
            valueInt=c.valueInt;
        }
        return *this;
    }

    
private:
    
};


int main()
{
    C c1(2);
    C c2=c1;//這里直接賦值
    std::cout<<"ptrInt "<<c2.ptrInt<<"  value "<<*c2.ptrInt<<std::endl;
    std::cout<<"valueInt "<<c2.valueInt<<std::endl;
    c1.DelIntV();

    std::cout<<"address  "<<c2.ptrInt<<"  value "<<*c2.ptrInt<<std::endl;
    std::cout<<"valueInt "<<c2.valueInt<<std::endl;
    std::cin.get();
    return 0;
}

結果

 

 

 


免責聲明!

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



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