【问题标题】:how to write the copy constructor of a class which has a pointer to this class as data member? [closed]如何编写具有指向该类作为数据成员的指针的类的复制构造函数? [关闭]
【发布时间】:2014-07-05 21:08:19
【问题描述】:

这是我的代码的一个简单示例

class base
{ 
    protected:
        int value; 
    public:
        base();
        base(const int);
        base(const base &);
        ~base();
];
class derived:public base
{
   protected:
        derived * next; // a pointer to the same datatype.
   public:
        derived();
        derived(const int);
        derived(const base &);
        derived(const derived &);// This is the problem.
        ~derived();
        ... ...
};

我的问题是派生类的拷贝构造函数怎么写,因为派生类内部有一个指向派生类的指针作为数据成员。我需要深拷贝来复制这个指针“派生*下一个”吗? “下一个 -> 下一个”或“下一个 -> 下一个 > 下一个”怎么样?它看起来像一个无限循环。

这是我目前写的内容

derived::derived(const derived & source):base(source)
{
    if(next)
        delete next;
    next = new derived(source.next);
}

【问题讨论】:

  • derived & next; 不是指针,而是引用。您还缺少一个虚拟析构函数。
  • 您可以从析构函数的主体中推断出您需要知道的一切。析构函数告诉你期望什么类不变量。推论。如果没有看到析构函数,我们不可能知道答案。
  • 您可以定义类的语义。 应该复制它做什么?
  • new derived(source.next) 传递的是指针而不是引用。您还应该定义一个停止条件。`
  • 不管你想要复制的语义是什么,我认为你的delete next有问题,因为你会删除源仍然指向的对象。

标签: c++ oop pointers copy-constructor deep-copy


【解决方案1】:

我认为这里的两个误解是构造函数中传递的参数不连贯和递归链中没有停止条件。由于没有理由停止,它可能会进入无限循环。假设结构不是圆形的,应该这样做:

derived::derived(const derived & source):base(source)
{
    if(source.next) // if next is NULL, stop copying
    {
        // get the object that is pointed instead of pointer itself
        next = new derived(*source.next);
    }
}

更新:

正如建议的那样,在构造函数中检查next 成员是毫无用处的。事实上,“防泄漏”安全必须在分配级别完成,实际指针值可能会丢失。仍然假设该结构是递归的良好候选者,您可以这样做是安全的:

derived& derived::operator=(const derived & source)
{
   if (this == &source) return *this; // copy of itself is already finish

   freeMem(*this); // ensuring that the structure is empty prior to copy

   if (source.next)
      this->next = new derived(*source.next); // re-use the copy ctor

   return *this;
}

考虑到freeMem 的这种可能性:

void derived::freeMem(const derived & source)
{
   if (source.next)
   {
      freeMem(*source.next); // this will force to delete from the end
      delete source.next;
      source.next = NULL;
   }
}

【讨论】:

  • 这是一个构造函数,先验值如何进入next
  • 复制参数可能已经有一个next 值,也可能已经有一个。 OP 的代码正在尝试以递归方式对整个结构进行深度复制。
  • 哦,是的,测试if (source.next) 非常有意义。但是你可以从测试中学到什么 if (next)... 它是未初始化的!
  • 在什么情况下delete next;next 类型的构造函数中可能是正确的?
  • next 是一个未初始化的指针。你说它可以有一个初始化的next成员,我问你怎么做?如果它有一个非空值,它就是一个野指针。 delete next; 在构造函数中不会有任何好处。
【解决方案2】:

如果 next 表示derived 的非循环链(又名列表),您的代码可能是:

derived::derived(const derived & source) :base(source.value)
{
    if (source.next) {   // if the source has a next pointer
        //delete next;   // don't delete ! 
        next = new derived(*source.next); // duplicate the object it contains 
    }
}

如果源有一个有效的next 指针,这将复制链中的所有后续对象,直到链结束(带有空值)。所有源对象将保持不变(所有依赖对象的副本)。

仅当您还创建 operator= 以避免该指针被无意的 = 覆盖时,这才有意义。请记住,您必须避免将对象分配给自身。

【讨论】:

    猜你喜欢
    • 2020-11-08
    • 1970-01-01
    • 2023-03-22
    • 1970-01-01
    • 1970-01-01
    • 2018-07-17
    • 1970-01-01
    • 1970-01-01
    • 2017-07-27
    相关资源
    最近更新 更多