依赖隐式声明的移动构造函数是否安全?

时间:2013-08-24 23:30:05

标签: c++ c++11 copy move move-constructor

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

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

  • 没有用户声明的复制构造函数
  • 没有用户声明的副本分配运算符
  • 没有用户声明的移动分配操作符
  • 没有用户声明的析构函数
  • 隐式声明的移动构造函数未定义为已删除
  • 如果用户声明了移动构造函数,则仍然可以使用关键字default
  • 强制生成隐式声明的移动构造函数

我的问题是:

  1. 依赖隐式自动移动构造函数是否安全?
  2. 如何检查它是否真的有效而不是默认的复制构造函数?
  3. 最后,最重要的是,这是一个好主意,为什么?或者总是更好地定义我自己的?
  4. 我更倾向于遵循三个规则并手动创建一个析构函数,一个复制和移动构造函数,以及一个复制和移动赋值运算符,但我只是好奇这个隐含一个。

2 个答案:

答案 0 :(得分:5)

以下是您的问题的答案:

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

答案 1 :(得分:3)

  

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

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

  

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

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

  

3。最后,最重要的是,这是一个好主意,为什么?或者是它   总是更好地定义自己的?

使您的特殊成员琐碎具有明显(且不断增长)的优势。一个普通的特殊成员是由编译器定义/提供的成员。您可以使用= default声明一个简单的成员。实际上,最后一句话是夸张的。如果您使用= default声明特殊成员,那么肯定不会是微不足道的。这取决于你的成员和基地。但是如果你明确地定义一个特殊的成员(如在C ++ 98/03中),那么肯定它不会是微不足道的。如果您可以选择用户提供的琐事,请选择琐碎

此外,您无需测试类型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生成零代码,并且消耗的编译时间可以忽略不计。