深度复制的分段错误

segmentation fault with deep copy

本文关键字:错误 分段 复制 深度      更新时间:2023-10-16

我试图对对象进行深度复制(用于写入时的复制),但遇到了分段错误。

我正在使用一个带有链表的哈希表。

    class Person
{
public:
    Person(const char * id,int nb)
    {
        this->id=strdup(id);
        this->nb=nb;
        this->init=init;
        this->next=NULL;
    }
    Person(const Person& rhs) :
    nb(rhs.nb),
    init(rhs.init),
    id(strdup(rhs.id)),
    next(rhs.next == NULL ? NULL : new Person(*rhs.next)) {}
    char* strdup(char const* in)
    {
        char* ret = new char[strlen(in)+1];
        strcpy(ret, in);
        return ret;
    }
    int nb,init;
    const char * id;
    Person *next;
};

    Hashtable deepcopy (const Hashtable& rhs)
    {
    num[0]=num[0]-1;
    Person** array=rhs.table;
    Hashtable autre;
    for (int i = 0 ; i < size; ++i)
        if (autre.table[i]!=NULL)
            autre.table[i] = new Person(*array[i]);
    return autre;
    num[0]=1;
}

我的类的属性Hashtable:

 Person **table;
    int* num;

编辑:这个问题似乎已经解决了我的深度复制有什么问题?我不明白。我认为我的复制构造函数很好,但我不明白为什么我在运行它时会出现seg错误。

必须修复此代码:

for (int i = 0 ; i < size; ++i)
    autre.table[i] = new Person(*array[i]);

table具有固定的大小,并且它填充了空指针。在循环中,您不会检查要复制的元素是否为空指针,因此您可以取消对它的隔离,并尝试复制甚至不存在的实体。

for (int i = 0 ; i < size; ++i) {
    if(array[i] != NULL) {
        autre.table[i] = new Person(*array[i]);
    }
}

附言:最好使用nullptr而不是NULL

我看到的问题:

  1. Person的默认构造函数。

    Person(const char * id,int nb)
    {
      this->id=id;
      this->next=NULL;
    }
    

    如果我使用

    Person foo()
    {
      char id[] = "John";
      return Person(id, 0);
    }
    Person a = foo();
    

    然后,用于在foo中保存"John"的堆栈内存现在被a保留,这将导致未定义的行为。

    您需要获得输入字符串的所有权。将std::string用于id,而不是char const*

  2. 复制Person的构造函数。

    声明

    id(rhs.id),
    

    如果您决定使用char const*作为id的类型,将是一个问题。如果您将其切换到std::string,则不会有问题。

  3. HashTable的复制构造函数生成table的浅复制。如果您决定删除HashTable的析构函数中的table,这将是一个问题。如果不在HashTable的析构函数中删除table,则表示内存泄漏。

  4. deepcopy中,在取消引用array[i]之前,您不会检查它是否为NULL。@alphabhoter已经指出了这一点。此外,您正在函数的局部变量autre中创建一个深度副本。除非您从函数中返回autre,否则深度副本在函数外不可见。

编辑由于不允许使用std::string,因此必须在默认构造函数和复制构造函数中为char const*分配内存。如果您的平台具有非标准函数strdup,并且您可以使用它,则可以将默认构造函数更改为:

Person(const char * id,int nb)
{
  this->id=strdup(id);
  this->next=NULL;
}

您需要对复制构造函数进行类似的更改。

如果你没有strdup或者不允许使用它,你可以定义它。这是一个非常简单的函数。

char* strdup(char const* in)
{
  char* ret = new char[strlen(in)+1];
  strcpy(ret, in);
  return ret;
}