这不是 根据操作员实现复制构造函数= 但是是一个更具体的问题。 (或者我喜欢思考。)

介绍

给定这样的(假设的)类:

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静态并依赖默认生成的复制构造函数和分配运算符。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top