【问题标题】:Making copy of any pointer member varible in copy constructor在复制构造函数中复制任何指针成员变量
【发布时间】:2016-06-23 19:23:39
【问题描述】:

我有一个 B 类,它的成员是指向 A 类对象的指针。在 A 类型的对象上使用复制构造函数时,它会被复制,但成员变量不会。 有没有办法复制 A 对象并自动复制其 B 成员? 以下代码显示了我试图解释的问题:

class A
{
public:
    A(char t_name)
    {
        name = t_name;
    }
    ~A()
    {
    }
    char name;
};

class B
{
public:
    A* attribute;

    B()
    {
        attribute = new A('1');
    }
    ~B()
    {}
};


int main()
{
    B* b_variable = new B;
    B* b_copy = new B(*b_variable);
    return 0;
}

【问题讨论】:

  • 编写复制构造函数 operator= 并修复 B 类的析构函数。请参阅有关 3 和/或 5 规则的帖子。stackoverflow.com/questions/4172722/what-is-the-rule-of-threestackoverflow.com/questions/4782757/…
  • 为什么你的代码在你的描述中颠倒了AB的意思? B 有一个成员指向 A
  • @Alex 你为什么要在这个时代保留指向某些东西的指针?为什么不保留A 成员,然后您的所有问题都解决了。
  • @NicolBolas 真实的事实。我正在编辑。
  • @JonathanMee 是的,这可能是一个选项,但我想知道如何处理这个问题。无论如何,我也会重新考虑你的选择:)

标签: c++ copy-constructor


【解决方案1】:

在 A 类型的对象上使用复制构造函数时,它会被复制,但成员变量不会。

您的代码从不调用 A 类中的任何复制构造函数。

您的代码在 B 类中调用了一个复制构造函数,它完全按照应有的方式进行操作,即将 attribute 的值复制到 A 类对象的 指针

换句话说 - 执行代码后,您有两个 B 类实例和一个 A 类实例。在两个 B 类实例中,attribute 指向同一个 A 类实例。

这(很可能)不是你想要的。

正如许多人已经指出的那样(例如,参见@lostbard 的答案),您需要 B 类中的复制构造函数来进行深度复制。需要深拷贝,因为 B 类有一个指针成员。

您还应该在 B 类析构函数和 main 中进行一些清理。

#include <iostream>
using namespace std;

class A
{
public:
    A(char t_name)
    {
        name = t_name;
    }

    ~A()
    {
    }
    char name;
};

class B
{
public:
    A* attribute;

    B()
    {
        attribute = new A('1');
    }

    /** Copy constructor */
    B(const B &copy)
    {
        // Make a new instance of class A
        attribute = new A(*copy.attribute);
    }

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

    ~B()
    {
        // Delete the class A instance
        delete attribute;
    }
};


int main()
{
    B* b_variable = new B;
    B* b_copy = new B(*b_variable);

    // Delete the two class B instances
    delete b_variable;
    delete b_copy;

    return 0;
}

类 A 中不需要复制构造函数。默认生成的将作为类 A 没有指针成员。

编辑

正如@Slava 所指出的,当你创建一个复制构造函数(三规则)时,你应该始终实现一个赋值运算符,所以我将它添加到上面的代码中。

有些人喜欢三规则是五规则,所以它也包括移动。在这里阅读更多:https://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming)

【讨论】:

  • 你仍然缺少赋值运算符
  • 为什么是A* attribute; 而不是A attribute
  • @lorro - 不知道 - 不是我的想法 - 询问 OP(或者阅读问题下的 OP 评论)
【解决方案2】:

虽然有很多解决方案,但我敢打赌,您迟早会实现通常的虚拟a.clone();。当您拥有 A 的派生类时,这将完美无缺(这或多或少是您将 A 作为指向堆分配对象的指针而不是作为值成员的唯一合理原因:))。

请注意,当您在层次结构中实现 clone() 时,C++ 支持协变指针返回类型。因此,如果 base 有一个返回的 virtual ,例如Clonable*,那么A的同样方法可以返回A*,A的后代ADerived可以返回ADerived*。对于clone() 的情况,请随意将“可以”理解为“应​​该”。

【讨论】:

  • 认为你走错了路。如果这是一个继承问题,那么clone 可能会有用。但由于这是一个包含关系,因此复制构造函数是迄今为止更好的选择。 clone 不符合三类规则。
  • 我不是说现在 OP 需要它,我是说我们迟早会得到它。否则我们为什么不简单地使用A attribute; 而不是A*?该类自己分配 A ,因此 A 对象池可能不是原因。至于三法则,我也不遵守:我倾向于制作 const 正确的类,其中赋值没有有效意义。也许我们不应该那么严格地接受这条规则,而是把它当作一个提示:)。
【解决方案3】:

为 A 和 B 创建一个复制构造函数:

class A
{
public:
    A(char t_name)
    {   
    name = t_name;
    }
    A(const A& copy)
    {   
        name = copy.name;
    }
    ~A()
    {
    }
    char name;
};

class B
{
public:
    A* attribute;

    B()
    {
        attribute = new A('1');
    }
    B(const B &copy)
    {
      attribute = new A(*copy.attribute);
    }
    ~B()
    {}
};

【讨论】:

  • A不需要创建copy ctor
  • 在这种情况下不需要它,因为该字段只是一个字符,但如果它是一个更复杂的问题,它可能成为必需的。
  • 关心假设情况真是太好了,尤其是当您不关心 dtor 中的内存泄漏和缺少赋值运算符时。
猜你喜欢
  • 1970-01-01
  • 2020-08-05
  • 2021-02-11
  • 1970-01-01
  • 2011-08-07
  • 2019-04-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多