首页 > 代码库 > c++ 副本构造器

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;
}

结果