如何在类包含指针时创建复制构造函数

how to create copy constructor when the class contains a pointer

提问人:F.M 提问时间:2/17/2018 最后编辑:noelicusF.M 更新时间:2/17/2018 访问量:1958

问:

我对复制构造函数概念有疑问。我写了一个这样的例子:

struct f1
{
     string x;
     string y;
     f1();
     ~f1();
};
struct f2
{
    int a;
    string b;
    f1 *ff;
    f2();
    ~f2();
};
class myclass{
    f2 *obj;
}

我发现结构 f2 应该有一个复制构造函数,因为该类包含指向分配内存的指针。但我不知道我应该如何创建它。

C++ 复制构造函数

评论

1赞 Some programmer dude 2/17/2018
根据用例,您可以使用 std::shared_ptr 并使用零规则
2赞 juanchopanza 2/17/2018
没有简单的答案。这实际上取决于谁拥有 所指向的对象。f2
0赞 Sebastian Redl 2/17/2018
以及它所代表的内容。
2赞 Jean-Baptiste Yunès 2/17/2018
您的替代方案是深拷贝(复制指向的内容)与浅拷贝(仅复制指针)。
3赞 john 2/17/2018
不仅是复制构造函数,而且是复制同化运算符。但实际上,除非你解释你期望发生的事情,否则这个问题是无法回答的。具体来说,在副本之后,原始副本和副本是共享分配的内存,还是各自拥有自己的副本?

答:

0赞 user9335240 2/17/2018 #1

您有很多选择:

主要二:

  1. 只需复制指针(浅层复制),只是不写构造函数,它将是隐式的,或者你可以写(在 ).struct f2

    f2(const f2 &original): f1(original.f1), a(original.a), b(original.b) { }
    

警告:不会复制成员变量的值。它只会复制引用,这使得两个 s 都引用同一个对象。f1f2.f1f1

f2 a;
...
f2 b(a); // Invokes the "copy" constructor
a.f1->x = "Something here";
std::cout << b.f1->x; // Will print "Something here"
  1. 创建一个深层副本,调用 的复制构造函数,并通过将新创建的副本写入f1this->f1struct f2

    f2(const f2 &original): f1(new f1(*original.f1)), a(original.a), b(original.b) { }
    

    同样,正如一位评论者所建议的那样,您还必须进行复制分配,因为您创建了一个复制构造函数(例如,除非您的对象是不可变的)

    f2 &operator=(const f2 &other) {
        if (this == &other) return; // If "self-assignment" just return.
    
        if (f1) { delete f1; } // Deletes the old one if any.
                               // The advisable alternative is to use
                               //    a smart pointer
        f1 = new f1(*other.f1);
        a = other.a;
        b = other.b;
        return *this;
    }
    

无论如何,您应该考虑使用智能指针:、 和 ,因为原始指针可能会导致很多错误。但是智能指针会为您(部分)管理内存,让您有更多机会思考您的逻辑。一些现代C++程序员说,你不应该很少使用,智能指针就可以了unique_ptrshared_ptrweak_ptrdelete

评论

0赞 john 2/17/2018
不能真的同意这个答案。建议 1 不起作用,因为 f1 是动态分配的。同样在建议 2 中,赋值运算符的实现在赋值给自己的情况下被窃听。
0赞 user9335240 2/17/2018
@john 将作业固定给自己,谢谢。但是为什么建议1不起作用?,我认为它会做一个“浅拷贝”,只是复制参考。(除非他需要“深度副本”)。
0赞 user9335240 2/17/2018
@john 尝试改进答案,您现在可以检查
1赞 john 2/18/2018
因为一旦复制了指针,并且两个对象具有相同的指针,就无法知道何时删除指针。如果析构函数确实删除了指针,则您将删除同一指针两次,如果没有,则存在内存泄漏。
0赞 user9335240 2/18/2018
@john 这就是为什么建议他使用智能指针,这种“共享原始指针”非常容易出错,但他“可能”有一个项目要求,例如,它由其他父对象管理,例如包含所有这些对象的组的文档模型,“拥有”所有这些对象。但是使用智能指针或不变性/复制可能是一个更好的主意。f1
-2赞 Wulf0x67E7 2/17/2018 #2

它几乎是一个普通的构造函数,它以自己类型的实例作为参数

f2(const f2& other):a(other.a),b(other.b),ff(new f1()){
    memcpy(ff,other.ff,sizeof(f1));//makes copy of ff
}

评论

2赞 bolov 2/17/2018
你不能对一个不可复制的对象做任何操作,你也无法对一个简单复制的对象执行此操作。你的代码非常非常错误。strcpystd::stringmemcpy
0赞 Wulf0x67E7 2/17/2018
好的,固定了字符串复制。不知道 std::string 的赋值已经是深拷贝了。我并不担心深度复制 f1,因为问题只是为 f2 制作一个复制构造函数。
0赞 Wulf0x67E7 2/17/2018
只是ff(new f1(*other.ff))然后?我想避免只使用隐式复制构造函数,当问题也与它们有关时。