首页 > 解决方案 > 包含指向指针的对象的深层副本

问题描述

我正在尝试为包含指针的对象创建一个复制构造函数,该指针引用其他指针等。以下代码是二叉树。

B树.h

{
public:
    vertex* root;

    BTree()
    {
        root = NULL;
    };

    ~BTree() {
        delete root;
        root = nullptr;
    };

    BTree(const BTree& p_BTree)       //copy constructor
    {                                                         
        root = new vertex(*p_BTree.root);
    }

    BTree& operator= (const BTree& other)                   //assignment operator
        {
            // Delete the existing class A instance
            delete root;
            // and create a new as a copy of other.attribute
            root = new vertex(*other.root);
        }

节点.h

class vertex{

public:

    int key;
    string data;
    vertex* leftChild;
    vertex* rightChild;
    vertex* parent;
    int height;


    vertex(string data){

        key = ID;
        this->data = data;
        leftChild = NULL;
        rightChild = NULL;
        parent = NULL;
        ID++;
    };

    vertex(){
        key = 0;
        leftChild = NULL;
        rightChild = NULL;
        parent = NULL;
    };

    vertex(vertex* node){
        key = ID;
        leftChild = node->leftChild;
        rightChild = node->rightChild;
        parent = node->parent;
    };

    ~vertex(){
        delete leftChild;
        delete rightChild;
        leftChild = nullptr;
        rightChild = nullptr;
    };

    void print(string indent){

        string indent2 = indent;
        cout <<indent << " " << data <<endl;

        if(leftChild != nullptr || rightChild != nullptr)
        {

            if(leftChild != nullptr){

                indent = "|" + indent;
                leftChild->print(indent);
            }else{

                cout << indent << endl;
            }

            if(rightChild != nullptr){

                indent2 = "|" + indent2;
                rightChild->print(indent2);
            }else{

                cout << indent2 << endl;
            }
        }

    }
};
#include "BTree.h"


int main() {

// Aufgabe 1
    BTree B;

    B.main();

// Aufgabe 2
    BTree C = B;   //Call copy constructor
    C.print();


// Aufgabe 3
    BST D;

    D.main();
    D.print(D.root);
    D.sortvector(); //neu hinzugefügt

// Aufgabe 4
    D.PrintLayers(D.root, 1);
}

问题是,当调用析构函数时,程序会崩溃,因为它试图释放已经被释放的内存。

对象 B 和 C 中的根(在 main 中)具有不同的内存地址,问题是对象 C 中的左子和右子。这些是浅拷贝而不是深拷贝。我不知道如何在这些属性的复制构造函数中执行此操作。

这是它在调试器中的样子:

在此处输入图像描述

标签: c++objectbinary-treecopy-constructordeep-copy

解决方案


我没有时间检查您的完整代码。

但是如果是,root = new vertex(*p_BTree.root);在你的复制构造函数中会是一个问题。rootnullptr

并且您vertex管理资源(它delete在析构函数中有一个),但不遵循三/五规则。

因此,一旦vertex创建了实例的副本,就会复制指针,并且两个实例vertex管理相同的指针,从而导致双重释放。

在树的节点中使用它是有问题的:

 ~vertex(){
        delete leftChild;
        delete rightChild;
        leftChild = nullptr;
        rightChild = nullptr;
    };

如果你有一棵深度很大的树,你可能会遇到 stackoverflow。这样做的原因是因为删除是递归完成的。您想在根中收集树的节点并在那里删除它们。

复制构造函数和复制赋值运算符中的深度复制也是如此vertex


进一步说明:

  • root = nullptr;在析构函数之后做delete是你不需要做的事情。对vertex.
  • 保持一致,不要混用NULLand nullptr。你应该坚持nullptr
  • root = NULL;在您的构造函数中应该使用成员变量的默认值或通过构造函数的成员初始化器列表来完成。对vertex.

推荐阅读