依赖隐式声明的move构造函数安全吗

Is it safe to rely on an implicitly declared move constructor?

本文关键字:构造函数 安全 move 声明 依赖      更新时间:2023-10-16

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

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

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

我的问题是:

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

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

以下是您问题的答案:

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

CCD_ 2。依赖隐式自动移动构造函数安全吗?

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

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

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

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

让您的特殊成员变得微不足道有着明显的(且不断增长的)优势。琐碎的特殊成员是由编译器定义/提供的。您可以用= default声明一个琐碎的成员。事实上,最后一句话是夸大其词。如果您用= default声明一个特殊成员,那么它肯定不是微不足道的。这取决于你的成员和基础。但是,如果您显式地定义了一个特殊的成员(如在C++98/03中),那么它肯定不会是微不足道的。如果您可以在用户提供的琐碎之间进行选择,请选择平凡

此外,您不需要测试类型X是否具有move构造函数。您需要测试,如果移动构造您的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生成的代码为零,并且消耗的编译时间可以忽略不计。