影响正确性的移动构造函数/赋值运算符的示例?

时间:2016-11-10 16:31:20

标签: c++ c++11

如果有任何没有实现移动语义的例子(即移动构造函数和移动赋值运算符)会影响程序的正确性而不仅仅是它的性能,我就会徘徊。

2 个答案:

答案 0 :(得分:1)

(我假设你暗示也没有办法复制这个课程。)

嗯,一个例子是std::unique_ptr。因为这个指针应该拥有动态分配new的对象的唯一所有权,所以允许复制构造函数没有任何意义,因为我们不能拥有2个所有者。但是,实现移动赋值运算符和移动构造函数仍允许移动已分配的对象。因为我们正在移动,所以移动的unique_ptr将不再具有对象的所有权,但现在移动到unique_ptr拥有此对象。这并不违反唯一所有权部分。如果我们没有这些移动语义,那么unique_ptr将会有更少的用例。

更一般地说,只要你没有尝试移动没有移动赋值操作符/移动构造函数的对象,那么从技术上来说,“将影响程序的正确性”的情况永远不会EM>”。非常具体的类具有此NotCopyable / NotMovable限制,例如std::mutex,因为这些类没有意义。请注意,只是从函数返回一个对象的前C ++ 17要求它已经是可复制的或可移动的,因此这些类的用例是有限的。

答案 1 :(得分:1)

这是任何值类型,其中实现复制语义是以下一个(或多个):

  • 非理性(又名:与班级设计相对立)

  • 不可能

  • 输入可能导致程序终止/死锁的成本

“无理”类别适用于类似unique_ptr的类型,其中类型的逻辑设计使复制变得荒谬。

“不可能”类别将包括系统外存在的许多API的包装类型。

考虑一些OpenGL对象的包装器类型。您可能会认为,因为OpenGL是一个可查询的API(您可以查询设置在其中的每个状态),您可以通过从旧对象获取状态并将其设置为新对象来合理地实现对象复制。

但由于OpenGL扩展,这是有缺陷的。它们可以为对象提供新的状态,在这些扩展之前编写的代码对此一无所知。

最后的类别听起来很奇怪。但是让我们来看看OpenGL包装器的想法。假设你实现了复制。而你正在复制一个缓冲对象(GPU内存的一部分)。

嗯......你在哪里复制?你是在具有OpenGL上下文当前的线程上做的吗?该对象是否在另一个线程中同时更新,以至于您已经在其他地方,以便您创建了竞争条件?

您可以尝试使用互斥锁来避免竞争条件,但现在您已经创建了非常真实的死锁的可能性。为什么?因为许多对象包含缓冲对象。复制这些对象自然需要复制它们包含的缓冲区。因此,您具有多重复制操作,必须锁定多个互斥锁才能完成其工作。如果它们正在复制相同的缓冲区,那么它可以与其他一些多拷贝操作发生死锁。

因此,要么您有机会遇到死锁,您就有可能获得不一致的内存副本......或者您根本不允许复制。

如果你的类型不允许复制,那么除非类型的设计另有说明,否则你应该允许移动。