2

这是我获得大部分信息的地方: http: //en.cppreference.com/w/cpp/language/move_constructor

显然,这些是隐式生成的移动构造函数起作用的条件:

  • 没有用户声明的复制构造函数
  • 没有用户声明的复制赋值运算符
  • 没有用户声明的移动赋值运算符
  • 没有用户声明的析构函数
  • 隐式声明的移动构造函数未定义为已删除
  • 如果存在用户声明的移动构造函数,仍然可以使用关键字强制生成隐式声明的移动构造函数default

我的问题是:

  1. 依赖隐式自动移动构造函数是否安全?
  2. 如何检查它是否真的有效,而不是默认的复制构造函数?
  3. 最后,也是最重要的,这是一个好主意吗?为什么?还是定义我自己的总是更好?

我更倾向于遵循三规则并手动创建析构函数、复制和移动构造函数以及复制和移动赋值运算符,但我只是对这个隐含的操作感到好奇。

4

2 回答 2

5

以下是您的问题的答案:

  1. “安全”是什么意思?当规则适用时,即子对象是可移动的,并且您没有对移动构造函数的生成进行任何操作,它将在存在时被创建和使用。但是请注意,很容易有一个不可移动的子对象,它会在某种程度上无形地抑制移动构造函数的创建。
  2. 要查看您的类是否有移动构造函数,只需在使用复制和移动构造函数时临时添加一个空的基本日志记录并强制移动/复制对象:它将记录相应使用的构造函数。
  3. 没有代码通常比任何代码都好。
于 2013-08-24T23:41:31.270 回答
3

1. 依赖隐式自动移动构造函数是否安全?

没有测试(隐式或显式),没有什么是安全的。

2. 如何检查它是否真的有效,而不是默认的复制构造函数?

测试。请参阅下面的示例测试。

3. 最后,也是最重要的,这是一个好主意吗?为什么?还是定义我自己的总是更好?

使您的特殊成员变得微不足道有明显的(并且不断增长的)优势。一个平凡的特殊成员是由编译器定义/提供的。您可以使用 . 声明一个普通成员= default。其实最后一句话有点夸张。如果你用 声明一个特殊成员= default,它肯定不会是微不足道的。这取决于你的成员和基地。但是如果你明确地定义了一个特殊的成员(如在 C++98/03 中),那么它肯定不会是微不足道的。如果您可以在user-providedtrivial之间进行选择,请选择trivial

此外,您不需要测试您的类型X是否具有移动构造函数。您需要测试,如果您移动构建您的X,它是否具有正确的异常安全性和正确的性能。如果X::X(const X&)完成了这项任务,那就这样吧。在那种情况下X::X(X&&)是没有必要的。

如果您希望您的类型X将有一个抛出的复制构造函数和一个更快的noexcept移动构造函数,这里有一个非常好的测试来确认它是这样的:

static_assert(std::is_nothrow_move_constructible<X>::value,
                                "X should move construct without an exception");

将此测试放在您的源代码/标题中。现在,无论您是隐式地,还是显式地声明或定义您的特殊成员,您都获得了一个几乎为零成本的具体编译时测试。static_assert生成零代码,并且消耗的编译时间可以忽略不计。

于 2013-08-25T00:54:03.177 回答