【问题标题】:Is declaring explicitly defaulted move constructor in every class that doesn't provide user-defined one a good practice?在每个不提供用户定义的类中声明显式默认的移动构造函数是一种好习惯吗?
【发布时间】:2018-02-27 07:25:38
【问题描述】:

有相当复杂的(对我来说)rules 定义了何时生成隐式默认的移动构造函数以及何时不生成。我担心的是不会生成默认的移动构造函数。另外我担心我(或其他人)将来修改类,隐式移动构造函数会消失。

有一个"advice" 表示“您始终可以显式调用可以使用= default 自动生成的函数的默认生成(这就是语法的用途)”。现在我问:这是个好主意吗?有什么理由不这样做吗?我想如果没有问题,那么我们就不需要默认的移动构造函数,移动构造函数总是会生成。但既然标准定义了如此严格的规则,这样做可能是有原因的。

【问题讨论】:

  • 我的观点:我认为明确表达总是合理和好的。
  • 仅仅因为你可以并不意味着你应该。与许多其他事情一样,这取决于情况和您的用例。这个问题没有单一的“是这样做”或“不这样做”的答案。
  • 在我看来——当然,这是正确的答案:学习规则然后最少编码。编码到最小的公分母对我来说总是一种气味。
  • “五规则”和“零规则”都很好,如果您遵循五规则,请正确获取 noexcept。

标签: c++ move-semantics


【解决方案1】:

考虑以下场景。您有一个可以使用自动生成的移动构造函数和析构函数的类:

class X {
      int i_;
   public:
      X(int i) : i_(i) { }
};

然后,将来,您添加一个成员变量,这需要用户定义的复制构造函数和析构函数:

class X {
      int i_;
      char* buf_;
      size_t n_;
   public:
      X(int i, size_t n) : i_(i), n_(n), buf_(new char[n]) { }
      X(const X& o) : i_(o.i_), n_(o.n_), buf_(new char[o.n_]) { memcpy(buf_, o.buf_, n); }
      ~X() { delete[] buf_; }
};

如果移动构造函数在这里是defaulted,那么新的类版本就会出错。

如果没有defaulted 移动构造函数,根据五规则 修改类就可以了,如果 5 个特殊函数之一需要用户定义,其他的也可能需要用户定义。如果需要,您现在必须手动定义移动构造函数。

【讨论】:

  • 即使没有任何 defaulted 移动或复制构造函数,您的类也是错误的。复制时会导致崩溃:coliru.stacked-crooked.com/a/f2f0031b99de7c8b。您必须添加用户声明的复制构造函数或将复制构造函数声明为deleted。
  • 如果一个类有用户声明的析构函数,那么省略默认复制构造函数的生成可能是有意义的。
  • @anton_rh 你说得对,这仅对移动构造函数有效,对复制构造函数无效,它也生成。
  • 但无论如何,您的示例间接显示了默认复制/移动构造函数的危害:coliru.stacked-crooked.com/a/55829815553804d0
  • @anton_rh 不客气。对于具有 deleted 复制构造函数的 non-copyable 类,这种推理可能更加强大,因为这样就更有可能忘记在更新的类中提供用户定义的移动构造函数。跨度>
猜你喜欢
  • 1970-01-01
  • 2021-10-30
  • 1970-01-01
  • 2019-02-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-11
  • 1970-01-01
  • 2011-04-08
相关资源
最近更新 更多