【问题标题】:Deep copy a class having a self reference pointer深拷贝具有自引用指针的类
【发布时间】:2018-10-23 07:30:25
【问题描述】:

我有一个 Employee 类,它带有指针变量标签和 char 类型的值以及一个自引用指针子级。我们还有另外两个整数变量“numAttributes”和“numChildren”。 “numChildren”指定如何将孩子添加到班级。 “numAttributes”是为了将来的目的。我必须分配和释放内存。为此,我正在尝试实现一个复制构造函数和一个析构函数。我面临的问题是,当它的子变量不为 NULL 时,我无法深度复制整个课程。我尝试过使用 memcpy() 以及提到的解决方案here。但我无法正确地做到这一点。当一切顺利时,它在析构函数中失败。到目前为止我尝试过的是:

#include<iostream>
#include<stdlib.h>
#include<string>
#include<map>
#define _CRT_SECURE_NO_WARNINGS
using namespace std;

class Employee
{
public:
    char* tag;
    char* value;
    int numAttributes;
    int numChildren;
    Employee* children;

    Employee(const Employee &attr)
    {
        cout << "Copy constructor called" << endl;

        numAttributes = attr.numAttributes;
        numChildren = attr.numChildren;

        tag = (char*)malloc(sizeof(char)*strlen(attr.tag) + 1);
        value = (char*)malloc(sizeof(char)*strlen(attr.value) + 1);
        strcpy(tag, attr.tag);
        strcpy(value, attr.value);

        if (attr.children == NULL)
            children = NULL;
        else
            children = attr.children; // shallow copy happening. Have to do deep copy if it has children
    }

    Employee(){
        cout << " constructor called" << endl;
        tag = NULL;
        value = NULL;
        children = NULL;
        numAttributes = 0;
        numChildren = 0;
    }
    ~Employee(){
        cout << "Destructor called" << endl;
        if (tag != NULL){
            free(tag);
            tag = NULL;
        }
        if (value != NULL){
            free(value);
            value = NULL;
        }
        if (children != NULL){
            free(children);
            children = NULL;
        }
    }

};

Employee createNode(const char* tag, const char* value, unsigned int numAttributes, unsigned int numChildren)
{
    Employee retNode;
    retNode.tag = (char*)malloc(sizeof(char)* (strlen(tag) + 1));
    strcpy(retNode.tag, tag);
    retNode.value = (char*)malloc(sizeof(char)* (strlen(value) + 1));
    strcpy(retNode.value, value);

    retNode.numAttributes = numAttributes;
    retNode.numChildren = numChildren;
//use this block if we are not initializing the children in the createOffset() method
        /*if (numChildren == 0){
        retNode.children = NULL;
        }
        else{
        retNode.children = (Employee*)malloc(sizeof(Employee)*numChildren);
        }*/

        return retNode;
    }
Employee createOffset()
{
    //Create and tag initial root node
    Employee retNode = createNode("offset", "value", 0, 1);

    retNode.children = (Employee*)malloc(sizeof(Employee)*retNode.numChildren);

    retNode.children[0] = createNode("prnt", "0000", 0, 0);

    return retNode; // Until here it is fine. This return calls the copy constructor first. As it has children the children must also be deep copied. Getting error here. Have to do deep copy the entire the class
}

Employee get(){

    return createOffset();
}

int main(){
    Employee node = get();
    getchar();
    return 0;
}

【问题讨论】:

  • 它到底应该做什么?由于它是复数“孩子”,它是否包含多个孩子?为什么它不是一个 c++ 容器而不是一个指针?你真的不应该在 c++ 中使用malloc
  • 我们应该正确分配和释放内存。我不确定为什么我们不使用容器。在我的项目中,代码已经编写好了,任务是修复内存泄漏,这与我在这里展示的场景相同。我必须清除分配的内存,因此我已经编写了析构函数,但是在析构函数中出现错误或者初始化没有正确进行。
  • 只有当你如你所说的正确处理内存时才会调用析构函数。也就是说,使用 c++ 方法来创建和删除对象。 malloc 不是这些方法之一
  • 即使,如果我使用 new 和 delete 运算符,我也会面临同样的问题
  • 然后先修复代码以使用它们,然后人们可以提供更多帮助。目前做错的太多了,尝试破译错误是有道理的。使用std::stringstd::vectornewdelete 等,所以它实际上是 c++ 而不是 c 并且错误地抛出了一个类。

标签: c++ c++11 visual-studio-2013 copy-constructor deep-copy


【解决方案1】:
struct Employee {
  std::string tag;
  std::string value;
  int numAttributes = 0;
  std::vector<Employee> children;
};

无需编写复制构造函数或析构函数,C++ 语言为您制作了一个在这里做正确的事情。

这被称为 0 规则。

Employee createNode(const char* tag, const char* value, unsigned int numAttributes, unsigned int numChildren)
{
  return {tag, value, numAttributes, std::vector<Employee>(numChildren)};
}

也短了很多。

Employee createOffset()
{
  //Create and tag initial root node
  Employee retNode = createNode("offset", "value", 0, 1);

  retNode.children[0] = createNode("prnt", "0000", 0, 0);

  return retNode;
}

完成了。

【讨论】:

    猜你喜欢
    • 2010-12-28
    • 2015-07-21
    • 1970-01-01
    • 1970-01-01
    • 2022-01-09
    • 1970-01-01
    • 2010-12-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多