题
这不是 根据操作员实现复制构造函数= 但是是一个更具体的问题。 (或者我喜欢思考。)
介绍
给定这样的(假设的)类:
struct FooBar {
long id;
double valX;
double valZ;
long valN;
bool flag;
NonCopyable implementation_detail; // cannot and must not be copied
// ...
};
我们无法通过默认生成的函数复制此内容,因为您既不能复制构造也不复制不可拷贝的对象。但是,该对象的这一部分是我们实际上对复制不感兴趣的实现细节。
它也是如此 为此编写交换函数没有任何意义, ,因为交换函数只能复制std ::交换所做的工作(减去不可复制)。
因此,如果我们要复制这些对象,我们将自己实现复制和复制操作员自己。这是通过分配其他成员来实现的。
问题
如果我们需要实现复制CTOR和操作员,是否应该根据复制操作员来实现复制CTOR,还是应该使用初始化列表“复制”代码?
也就是说:
FooBar& operator=(FooBar const& rhs) {
// no self assignment check necessary
id = rhs.id;
valX = rhs.valX;
valZ = rhs.valZ;
valN = rhs.valN;
flag = rhs.flag;
// don't copy implementation_detail
return *this;
}
我们应该写A)
FooBar(FooBar const& rhs) {
*this = rhs;
}
或b)
FooBar(FooBar const& rhs)
: id(rhs.id)
, valX(rhs.valX)
, valZ(rhs.valZ)
, valN(rhs.valN)
, flag(rhs.flag)
// don't copy implementation_detail
{ }
答案的可能方面是性能与可维护性与可读性。
解决方案
通常,我更喜欢b)而不是a),因为它明确避免了成员的任何默认构造。对于INT,双打等,这不是考虑因素,但可以适用于具有昂贵操作或副作用的成员。如果您不必考虑添加和删除会员时,您不必考虑这种潜在的成本/问题,那就更可维护了。初始评估列表还支持参考和非默认构建元素。
另外,您可以拥有非“实现详细信息”成员的子结构,并让编译器沿线生成复制代码:
struct X
{
struct I
{
int x_;
int y_;
} i_;
int z_;
X() { }
X(const X& rhs)
: i_(rhs.i_), z_(0) // implementation not copied
{ }
X& operator=(const X& rhs)
{
i_ = rhs.i_;
return *this;
}
};
其他提示
通常,您以复制构造函数(@Roger Pate的版本)来实现作业运算符:
FooBar& operator=(FooBar copy) { swap(*this, copy); return *this; }
friend void swap(FooBar &a, FooBar &b) {/*...*/}
这需要提供 swap
功能交换相关成员(除了 implementation_detail
就您而言)。
如果 swap
不能投入这种方法可以保证对象不会处于某些不一致的状态(只有部分成员)。
但是,在您的情况下,由于复制构造函数和作业运算符都不能以作业运算符(a)抛出实现的复制构造函数(a)也很好,并且在两个地方都具有几乎相同的代码(b)更可维护。
如果您真的很想复制std ::交换,为什么不将实现细节以外的所有内容放入结构中?
struct FooBarCore {
long id;
double valX;
double valZ;
long valN;
bool flag;
// ...
};
struct FooBar {
FooBarCore core_;
NonCopyable implementation_detail; // cannot and must not be copied
};
然后,您可以在复制函数中使用std :: swap作为此结构 FooBar
.
FooBar& operator=(const FooBar &src) {
FooBarCore temp(src.core_)
swap(temp,*this.core_);
return *this;
}
好吧,另一个尝试,根据我的评论 这个答案.
将实现_detail包装在可复制类中:
class ImplementationDetail
{
public:
ImplementationDetail() {}
ImplementationDetail(const ImplementationDetail&) {}
ImplementationDetail& operator=(const ImplementationDetail&) {}
public: // To make the example short
Uncopyable implementation_detail;
};
并在您的鹅卵中使用此课程。 Foobar的默认生成的复制构造函数和复制分配运算符将正确工作。
也许它甚至可以源于无与伦比,所以您不会得到 implementation_detail.implementation_detail
整个代码。或者,如果将代码控制到实施_Detail类中,只需添加空复制构造函数和空任务操作员。
如果复制构造函数不需要复制实现_detail,并且仍然是正确的(我怀疑后者,但让我们暂时假设它),则实现_detail是多余的。
因此,解决方案似乎是:使实现_Detail静态并依赖默认生成的复制构造函数和分配运算符。