我正在看CppCon2014, Michael Caisse, The Canonical Class talk, 在28' 31",他显示了一个图表,显示用户何时提供了一些复制控制,编译器将如何隐式提供或不提供其余的:
我没有用'#34;删除" - 似乎标准说,当用户提供移动构造函数或移动赋值时,复制构造函数和复制赋值将被删除 - 好的,但为什么呢?
让我们更加具体。
Q1。当用户提供移动构造函数时,复制构造函数和复制构造函数将被删除 - 这是否意图避免错误的用法,为构造函数或赋值提供左值,左值变为无效?这是显式强制传递给构造函数或赋值为rvalue的参数吗?
Q2。当用户提供移动分配时,复制分配将被删除 - 这与Q1相同吗?
Q3。当用户提供移动分配时,复制构造函数将被删除 - 为什么这样?移动赋值似乎不会搞乱复制构造函数吗?
答案 0 :(得分:1)
考虑到一些不幸的历史,这是最不安全的方式。
用户定义析构函数只有一个原因,即我们正在管理一个本身不是RAII的资源。如果我们正在管理资源,它就不会很好地复制(或移动自己)。这些操作需要手动管理。
如果我们提供析构函数,语言应该隐式删除复制和移动运算符。不幸的是,这在早期没有预见到,所以我们有3的规则 - “如果你定义了一个析构函数,你必须定义一个复制构造函数和复制赋值”。
这条规则是为了让我们远离语言陷阱。
有人提议关闭这个漏洞(IIRC),据我所知,它被拒绝了,因为它会破坏太多的现有代码(虽然坦率地说,所有这些现有代码都是危险错误的,这本来是没什么坏事。)
所以我们就在这里。原则是,如果您手动管理资源,则必须在所有5个操作中对其进行管理。如果您手动编写其中一个操作,则需要将它们全部写入。
只是自动删除复制构造函数/复制赋值语言仍然存在。
答案当然是永远不要手动管理资源。由于我们有自定义删除器的智能指针,可以为我们管理资源,因此我们很少需要。当我们这样做时,我们应用5,3的规则...但是我们应该总是更喜欢无规则 - 使用托管资源并且不定义任何析构函数,复制,移动或赋值运算符,只需让编译器正确执行的事情。