如果副本足夠昂貴,我會將該類視爲在簽名中不可複製。在語義上,事物只有在你想要它們的時候纔是可複製的,而昂貴的拷貝是決定「不可複製」的合理理由。
某些東西被複制的能力並不意味着它需要在可複製的類型中實現。該類型的實現者可以決定它是否應該在語義上可複製。
我不會稱這種操作產生昂貴的副本「副本」,而是「克隆」或「重複」。
一種方式,你可以這樣做:
#include <utility>
template<typename T>
struct DoCopy {
T const& t;
DoCopy(T const& t_):t(t_) {}
};
template<typename T>
DoCopy<T> do_copy(T const& t) {
return t;
}
struct Foo {
struct ExpensiveToCopy {
int _[100000000];
};
ExpensiveToCopy* data;
Foo():data(new ExpensiveToCopy()) {}
~Foo(){ delete data; }
Foo(Foo&& o):data(o.data) { o.data = nullptr; }
Foo& operator=(Foo&& o) { data=o.data; o.data=nullptr; return *this; }
Foo& operator=(DoCopy<Foo> o) {
delete data;
if (o.t.data) {
data=new ExpensiveToCopy(*o.t.data);
} else {
data=new ExpensiveToCopy();
}
return *this;
}
Foo(DoCopy<Foo> cp):data(cp.t.data?new ExpensiveToCopy(*cp.t.data):new ExpensiveToCopy()) {};
};
int main() {
Foo one;
// Foo two = one; // illegal
Foo three = std::move(one); // legal
Foo four;
Foo five = do_copy(three);
four = std::move(three);
five = do_copy(four);
}
這有點類似於你可以寫std::move
像前右值引用的存在語義的方式,用類似的缺點,以這樣的技術,即該語言本身不知道你在做什麼樣的詭計。
它具有的優點是,上述do_copy
的語法是類似於std::move
語法,以及它允許使用傳統的表達式,而無需創建的Foo
瑣碎實例然後構造的另一個變量等的副本
如果我們想把它當作可複製的情況是常見的(如果要避免),我會在知道duplicate
方法的類上寫一個複製包裝。
我想'複製'成員函數的問題是它打破了所有使用賦值運算符的模板代碼。 – Pubby 2013-04-06 19:40:20