c++ - 如何在深拷贝中使用构造函数分配内存?

标签 c++

我正在尝试理解深拷贝。但是我只是对通过调用构造函数动态分配内存感到困惑

这是我成功的深拷贝程序:

#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 个指针)或者指针是否与静态数据成员相同(那么不需要深度复制)?类的所有对象均指一个指针。

最佳答案

如果您创建该类的两个实例,它们将有两个不同的 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= 未定义。
你的类(class)看起来像这样:

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

当你在类里面处理动态分配的内存时,那很糟糕。让我们看看在您的 main 中会发生什么:

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" (复制构造函数、复制赋值运算符和析构函数)

关于c++ - 如何在深拷贝中使用构造函数分配内存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31775902/

相关文章:

c++ - 如何在 VSCODE 中使用 OpenCV C++

c++ - 重载 operator() 并在类中使用

c++ - 为什么将对象引用参数传递给线程函数无法编译?

c++ - 图像扭曲与 VTK?

c++ - typeinfo 和dynamic_cast 外部未解析

c++ - 使用 GDB 调试

c++ - 在 Qt 中移动 Snake 时遇到问题

c++ - 在模板实例化中包含和排除类型

c++ - QFile + QTextStream 只读文件的一部分

C++缓冲流IO