我应该在什么条件下考虑实现移动构造函数和移动运算符
Under what conditions should I be thinking about implementing a move constructor and a move operator?
对于标准的复制构造函数和赋值运算符,如果我的类实现了析构函数,我总是考虑实现它们或delete
对于新的移动构造函数和移动运算符,考虑是否需要实现的正确方法是什么?
作为从 pre-C++0x 转换系统的第一步,我可以只delete
默认的移动构造函数和移动运算符,还是应该不理会它们?
您不必担心它,从某种意义上说,当您用户声明析构函数(或 12.8/9 中列出的任何其他内容(时,这会阻止生成默认的移动构造函数。因此,与副本的风险不同,即默认是错误的。
所以,作为第一关,不要管他们。在现有代码中,C++11 移动语义可能允许移动,而 C++03 指示副本。你的类将继续被复制,如果这在 C++03 中没有导致性能问题,那么我无法立即想到为什么它会在 C++11 中出现任何原因。如果它确实在 C++03 中导致性能问题,那么您有机会修复代码中以前从未解决过的错误,但这是一个机会,而不是义务;-(
如果您稍后实现移动构造和赋值,它们将被移动,特别是如果您认为类的 C++11 个客户端不太可能使用"交换化"来避免复制,更有可能按值传递您的类型等,则您需要这样做C++03 客户端。
在 C++11 中编写新类时,您需要在与 C++03 中考虑和实现swap
的相同标准下考虑和实现 move。可以复制的类实现了 C++11 的"可移动"概念(就像可以在 C++03 中复制的类可以通过 std
中的默认实现进行交换一样(,因为"可移动"没有说明源处于什么状态 - 特别是它允许保持不变。因此,副本作为移动是有效的,它不一定是有效的,对于许多类,您会发现与"好"的移动或交换不同,副本可以抛出。
必须为类实现 move,并且您还有一个可移动但不可复制的数据成员(因此也没有默认的复制构造函数(。这时,移动在语义和性能上都变得很重要。
对于 C++11,由于库的编写方式,您很少需要提供析构函数或复制语义。编译器提供的成员几乎总是做得很好(前提是它们正确实现:MSVC 迫使您手动实现许多移动语义,这非常麻烦(。
如果必须实现自定义析构函数,请使用以下方法:
- 实现一个移动构造函数和一个按值获取的赋值运算符(使用 copy&swap:请注意,你不能使用
std::swap
,因为它使用赋值。您必须自己提供私人交换(。注意异常保证(查找std::move_if_noexcept
(。 - 如有必要,实现复制构造函数。否则,请将其删除。请注意,非默认复制语义很少有意义。
算作自定义析构函数:在声明虚拟析构函数时提供或删除复制 + 移动语义。
由于它们被用作优化,如果优化适用于您的类,则应实现它们。如果您可以从即将销毁的临时对象中"窃取"类持有的内部资源。std::vector 是一个完美的例子,其中 move 构造函数只将指针分配给内部缓冲区,将临时对象留空(有效地窃取元素(。
- 为什么不调用移动构造函数?(默认情况下只有构造器,没有别的)
- std::vector::p ush_back() 不会在 MSVC 上编译具有已删除移动构造函数的对象
- 仅包含可移动 std::map 的类的移动构造函数不起作用
- 为什么调用复制构造函数而不是移动构造函数?
- 基类中的默认析构函数禁用子类中的移动构造函数(如果有成员)
- 从具有按值捕获的 lambda 移动构造 std::函数时,移动构造函数调用两次
- 移动构造函数和右值引用
- 为什么 std::memmove 中联合的默认非平凡移动构造函数C++?
- 具有专用化的模板类中的可靠条件复制和移动构造函数
- C++:为什么不调用移动构造函数?
- 移动构造函数永远不会被调用
- C++:关于使用 Stroustrup 示例移动构造函数/赋值的问题
- 运算符+ 的规范实现涉及额外的移动构造函数
- C ++为什么在移动构造函数中需要移动/前进
- 为什么在删除"移动构造函数"时使用"复制构造函数"?
- 为什么这里不调用移动构造函数?
- 隐式移动构造函数
- 如何为具有私有成员的派生类实现移动构造函数
- 为什么不调用移动构造函数
- 是否可以避免在以下代码中复制/移动构造函数的需要?