簡體   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