如何在深层复制中使用Constructor分配内存?

时间:2015-08-02 19:45:48

标签: c++

我正在尝试了解Deep Copy。但是我只是通过调用Constructor 来分配动态内存。

以下是我成功的Deep copy程序:

#include<iostream>
using namespace std;
class A{
    public:
    int *p;
    A(){
        p=new int;
    }
    void set(int b){
        *p=b;
    }
    int get(){
        return *p;
    }
    void operator=(const A &k){
        p = new int;
        *p=*(k.p);
    }
    ~A(){
        delete p;
    }
};
int main()
{
    A obj;
    obj.set(3);
    A obj1;
    obj1=obj;
    obj1.set(5);
    cout << obj.get() << endl;
    cout << obj1.get() << endl;
}

现在我只想问我创建了两个对象,构造函数将调用两次,并且在构造函数中有动态内存正在分配。

然后我的问题是指针应指向两个不同的动态内存位置(2个对象和2个指针)或指针与静态数据成员相同(那么不需要深层复制)?所有类对象的平均指针。

1 个答案:

答案 0 :(得分:0)

如果您创建该类的两个实例,它们将有两个不同的p成员,每个成员在内存中包含不同区域的不同地址,是的。
你可以判断你是否运行你的程序:它会显示3和5,如果指针是相同的,它会显示5次。

编辑:按照要求,提供了一些补充说明(以及评论中所说内容的摘要)

首先,你的operator=正在泄漏内存,而你应该记得在重新分配之前释放已在p中分配的内存:

void operator=(const A &k){
    delete p;
    // as JoshuaGreen states in the comments, you can set p to nullptr
    // here, that way, if new fails and throws, p will be set to nullptr
    // and you'll know it doesn't contain anything (you'll have to test
    // it in other methods to benefit from this modification though,
    // but it will be safer)
    p = nullptr;
    p = new int;
    *p=*(k.p);
}

虽然在这种特殊情况下,您可以避免重新分配:

void operator=(const A &k){
    // p = new int; // not needed
    *p=*(k.p);
}

现在,重载分配operator=确实很重要(并且你实际上忘了重载复制构造函数),让我们看看如果这个赋值operator=不是&#会发生什么? 39; t定义。
你的课程看起来像这样:

#include<iostream>
using namespace std;
class A{
public:
    int *p;

    A(){
        p=new int;
    }

    void set(int b){
        *p=b;
    }

    int get(){
        return *p;
    }

    ~A(){
        delete p;
    }
};

但实际上,编译器会为您生成一个隐式定义的默认复制构造函数和默认赋值运算符=。当然,你没有看到他们的实现,但是他们的行为与这样定义的类似:

#include<iostream>
using namespace std;
class A{
public:
    int *p;
    A(){
        p=new int;
    }

    A(const A& other) :
    p(other.p) {} // ! we're copying the pointer instead of reallocating memory

    void set(int b){
        *p=b;
    }

    int get(){
        return *p;
    }

    A& operator=(const A& other){
        p = other.p; // same here!
    }

    ~A(){
        delete p;
    }
};

当你上课处理动态分配的内存时,这很糟糕。让我们看看你的主要会发生什么:

int main()
{
    // allocate a new pointer to int, let's call it p
    A obj;
    // set the content of p to 3
    obj.set(3);
    // allocate a new pointer to int, let's call it p1
    A obj1;
    // /!\
    // instead of copying the content of p to the content of p1, we're
    // actually doing p1 = p here! we're leaking memory AND the two
    // objects point on the same memory!
    obj1=obj;
    // set the content of p1 to 5, but p1 is now equal to p because of
    // the bad assignment, so we're also setting p's content to 5
    obj1.set(5);
    // print the content of p (5)
    cout << obj.get() << endl;
    // print the content of p1 (5)
    cout << obj1.get() << endl;
}
// delete the contents of p and p1 /!\ we're actually deleting the same
// allocated memory twice! that's bad

这就是你必须重新定义"big three"(复制构造函数,复制赋值运算符和析构函数)的原因

相关问题