如果副本足够昂贵,我会将该类视为在签名中不可复制。在语义上,事物只有在你想要它们的时候才是可复制的,而昂贵的拷贝是决定“不可复制”的合理理由。
某些东西被复制的能力并不意味着它需要在可复制的类型中实现。该类型的实现者可以决定它是否应该在语义上可复制。
我不会称这种操作产生昂贵的副本“副本”,而是“克隆”或“重复”。
一种方式,你可以这样做:
#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