Глубокая копия класса, имеющего указатель на себя - PullRequest
0 голосов
/ 23 октября 2018

У меня есть класс Employee с тэгом переменных-указателей и значениями типа char и дочерними указателями с самотсылкой.У нас также есть еще две целочисленные переменные "numAttributes" и "numChildren".«numChildren» указывает, как дети могут быть добавлены в класс.«numAttributes» для будущих целей.Я должен выделить и освободить память.Для этого я пытаюсь реализовать конструктор копирования и деструктор.Проблема, с которой я сталкиваюсь, заключается в том, что я не смог глубоко скопировать весь класс, когда у него есть дочерние переменные не NULLЯ попытался использовать memcpy (), а также решение, упомянутое здесь .Но я не мог сделать это правильно.Когда все идет хорошо, это терпит неудачу в деструкторе.Что я пробовал до сих пор:

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

1 Ответ

0 голосов
/ 23 октября 2018
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;
}

и готово.

...