繁体   English   中英

仅使用移动语义复制对象

[英]Copying objects with only move semantics

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

假设我正在使用使用移动语义(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决定强制移动所有内容(显然,他不知道如何使用移动语义设计类)。 但是,在我的代码中,我需要拥有VeryHeavyObject副本

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

PS:我已经尝试过,但是我不能真正联系图书馆的作者(我认为他正在休假)。

你不能。

但是,只要您有足够的权限来访问其内部结构(getter等),则可以自己构造一个克隆

一个明确定义的接口,我们将假定是这种情况,某些方法可能不可用,因为作者出于性能原因希望阻止某些用途。 一个著名的示例是std::list ,它不包含[]运算符,因为与其他容器(例如std::vector O(1)中的O(1)相比,它具有O(n)复杂度。

在这种情况下,图书馆的作者希望不鼓励使用副本,因为正如您在问题中所指出的那样,这样做非常昂贵。 但这并不意味着这是不可能的。 如果确实需要这样做,则可以编写自己的Clone()函数,该函数适当地从原始的VeryHeavyObject中获取数据,并使用这些数据构造一个新数据,然后使用std::move将其返回。 由于我们还没有VeryHeavyObject的接口, VeryHeavyObject我们无法尝试这样做,但是我敢肯定您可以。

可能不可能。

该类已将副本声明为私有,但是我们看不到是否定义了函数。 您似乎假设该类具有复制操作,该操作对您而言是隐藏的,以阻止您执行缓慢的操作,但事实并非如此。 有些对象根本无法复制。 例如,考虑流。

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

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

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

如果实现了副本分配运算符,那么即使它是private ,您也可以找到一种调用它的方法 但是,这对于复制构造函数不起作用,您不能使用指向构造函数的指针。 作为一种残酷的黑客,您可以在包含其标头之前#define private public :它是未定义的行为,但可能会在您使用的实现上起作用。 分叉第三方资源会更好。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM