1

首先,让我带大家进入我的思想高速公路(简单地说,我只是在想象这些事情

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

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

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

PS:我试过了,但我无法真正联系到图书馆的作者(我认为他正在度假)。

4

4 回答 4

6

你不能。

但是,只要您对它的内部(getter 等)有足够的访问权限,那么您就可以自己构建一个克隆

于 2012-11-28T09:29:15.893 回答
2

一个定义良好的接口,我们将假设是这种情况,某些方法可能不可用,因为作者出于性能原因不鼓励某些用途。一个著名的例子是std::list,它不包括[]运算符,因为与其他容器相比,它具有O(n)复杂性O(1),例如std::vector.

在这种情况下,图书馆的作者不鼓励使用副本,因为正如您在问题中所说的那样,它的成本非常高。但这并不意味着它是不可能的。如果您确实需要这样做,您可以编写自己的Clone()函数,该函数根据需要从原始数据中获取数据,VeryHeavyObject使用这些数据构造一个新函数并使用std::move. 由于我们没有接口,VeryHeavyObject我们无法尝试这样做,但我相信你可以。

于 2012-11-28T09:24:15.393 回答
2

这可能是不可能的。

该类已将副本声明为私有,但我们看不到这些函数是否已定义。您似乎认为该类有一个复制操作,它对您隐藏起来以阻止您做一些缓慢的事情,但情况可能并非如此。有些对象根本无法复制。例如,考虑流。

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

也许这个类有足够的公共访问器,你可以查询它以获得你需要的状态,并构造一个与之匹配的新对象。如果是这样,那么您可以合理地向该课程的作者抱怨它应该是可公开复制的。如果不是,那么它可能具有无法复制的状态。

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

如果实现了复制赋值运算符,那么即使它是私有的,您也可以破解一种调用它的方法。但是,这不适用于复制构造函数,您不能将指针指向构造函数。作为一个残酷的黑客,你可以 #define private public在包含它的标题之前:它是未定义的行为,但它可能适用于你正在使用的实现。分叉第三方来源会更好。

于 2012-11-28T10:06:03.770 回答
1

通常,不修改类是不可能的,因为可能存在您无法访问的私有数据。如果浅拷贝就足够了,这可能是可能的,因为那样你应该能够使用memccpy. (注意,如果类没有任何虚拟成员或指针,浅拷贝和深拷贝是一样的)。

于 2012-11-28T09:31:08.393 回答