仅使用移动语义复制对象

时间:2012-11-28 09:12:47

标签: c++ c++11 rvalue-reference

在其他任何事情之前,让我带你们走进我的想法的高速公路(简单地说,我只是想象这些事情

假设,我使用的是使用移动语义(r值引用)的第三方库类。这是它的定义:

class VeryHeavyObject {
    VeryHeavyObject(const VeryHeavyObject& obj); // copy constructor
    VeryHeavyObject& operator= (const VeryHeavyObject& obj); // copy operator

public:
    VeryHeavyObject(); // constructor

    VeryHeavyObject(VeryHeavyObject&& obj); // move constructor
    VeryHeavyObject& operator= (VeryHeavyObject&& obj); // move operator

    // ....
};

显然,作者真正关心的是复制VeryHeavyObject的成本,并决定强迫一切都被移动(更明显的是,他不知道如何设计具有移动语义的类)。但是,在我的代码的某些方面,我需要VeryHeavyObject副本

嗯,核心问题是: 如何只使用移动构造函数和移动运算符复制对象?

P.S。:我已经尝试但我无法联系图书馆的作者(我认为他正在休假)。

4 个答案:

答案 0 :(得分:6)

你不能。

但是,如果您对其内部(getter等)有足够的访问权限,那么您可以自己构建 clone

答案 1 :(得分:2)

一个定义良好的界面,我们假设是这种情况,某些方法可能无法使用,因为作者想要出于性能原因而不鼓励某些用途。一个众所周知的示例是std::list,其中不包含[]运算符,因为与其他容器中的O(n)相比,O(1)具有std::vector复杂度,例如Clone()

在这种情况下,图书馆的作者想要阻止使用副本,因为正如您在问题中所说,这是非常昂贵的。但这并不意味着它是不可能的。如果您真的需要这样做,您可以编写自己的VeryHeavyObject函数,根据需要从原始std::move获取数据,使用这些数据构造一个新数据并使用VeryHeavyObject返回它。由于我们没有{{1}}的界面,我们无法尝试这样做,但我相信你可以。

答案 2 :(得分:2)

可能无法实现。

该类已将声明副本设为私有,但我们无法查看这些函数是否已定义。你好像假设这个类有一个复制操作,它隐藏着你,阻止你做一些缓慢的事情,但情况可能并非如此。有些对象根本无法复制。例如,考虑流。

你不会指望在C ++ 11中私有声明但未定义的函数,但是没有法律可以反对它。无论如何,即使有一个已实现的私有复制功能,它可能是私有的(也许它只能在某些受控情况下使用:类内部知道如何安全地使用它而你不这样做)。因此,如果没有公共副本,那么就该类的API而言,它无法复制。

也许该类有足够的公共访问器,您可以根据需要查询它,并构造一个匹配它的新对象。如果是这样,那么你可以合理地向班级作者抱怨它可以公开复制。如果没有,那么也许它的状态不能重复。

任何提供唯一访问某些内容(流,驱动程序,锁)的内容都有理由不可复制,因为原始文件和副本不能同时提供对同一内容的唯一访问权限。不可否认,dup意味着即使文件描述符也不能物理地提供对某些内容的唯一访问,更不用说包装它们的流。但是一个流的状态涉及尚未写入的缓冲数据,这意味着复制它们会引入该类旨在保护您的复杂性。因此,从逻辑上讲,您通常使用流,就好像它是访问某些内容的唯一方式。

如果实施了复制赋值运算符,那么您可以破解a way to call it even though it's private。但是,这对复制构造函数不起作用,你不能指向构造函数。作为一个残酷的黑客,你可以 #define private public在包含它的标题之前:它是未定义的行为,但它可能适用于你正在使用的实现。分叉第三方来源会更好。

答案 3 :(得分:1)

通常,如果不修改类,则无法进行,因为可能存在无法访问的私有数据。如果浅拷贝就足够了,因为那样你should be able to do it with a memccpy。 (请注意,如果类没有任何虚拟成员或指针,则浅层和深层副本相同)。