根据标准,
如果类 X 的定义没有显式声明移动构造函数,则当且仅当
— X 没有用户声明的复制构造函数,
— X 没有用户声明的复制赋值运算符,
— X 没有用户声明的移动赋值运算符,并且
— X 没有用户声明的析构函数。
现在以下无法编译
# include <utility>
class Foo
{
public:
Foo() = default;
Foo(Foo const &) = delete;
};
int main()
{
Foo f;
Foo g(std::move(f)); // compilation fails here
return 0;
}
因此,删除的函数似乎被视为用户定义的,这是有道理的(这不是它的默认实现)。但是,在这种特殊情况下,删除的复制构造函数/赋值会如何混乱默认移动构造函数/赋值?
我认为这个问题具有实际重要性,因为手动生成和特别是。维护这样的默认函数很容易出错,同时,(正义的)增加类的使用,例如std::unique_ptr
因为类成员使得不可复制的类比以前更加常见。
user-declared
意味着要么用户提供的 (defined由用户),明确默认 (= default
) or 明确删除 (= delete
)与隐式默认/删除(例如您的移动构造函数)相反。
所以就你而言,yes移动构造函数是隐含地已删除,因为复制构造函数是明确地已删除(因此用户声明的).
但是,在这种特殊情况下,删除的复制构造函数/赋值会如何混乱默认移动构造函数/赋值?
不会,但标准并不能区分这种情况和复杂的情况。
最短的答案是,有一个隐含地定义的移动构造函数明确地删除的复制构造函数might在某些情况下是危险的,当你有一个用户自定义析构函数和没有用户自定义复制构造函数(参见三/五/零规则 http://en.cppreference.com/w/cpp/language/rule_of_three)。现在,您可以认为用户定义的析构函数不会删除复制构造函数,但这只是一个flaw使用无法删除的语言,因为它会破坏许多旧的(坏的)程序。引用 Bjarne Stroustrup 的话:
在理想的世界中,我认为我们会决定“不生成”作为默认值,并为“给我所有常规操作”提供一个非常简单的符号。 [...]此外,“无默认操作”策略会导致编译时错误(我们应该有一个简单的方法来修复),而默认生成操作策略会导致运行时之前无法检测到的问题。
您可以阅读有关此内容的更多信息N3174=10-0164 http://www.stroustrup.com/move.pdf.
请注意,大多数人都遵循三/五/零规则 http://en.cppreference.com/w/cpp/language/rule_of_three,我认为你应该这样做。通过隐式删除默认的移动构造函数,该标准可以“保护”您免受错误的影响,并且应该在很长一段时间内通过在某些情况下删除复制构造函数来保护您(请参阅 Bjarne 的论文)。
如果您有兴趣,请进一步阅读:
- 执行零规则 http://accu.org/index.php/journals/1896
- N3153 - 隐式移动必须进行 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3153.htm
- N3174 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3174.pdf
- N3201 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3201.pdf
我认为这个问题具有实际重要性,因为手动生成和特别是。维护这样的默认函数很容易出错,同时,(正义的)增加类的使用,例如std::unique_ptr
因为类成员使得不可复制的类比以前更加常见。
将移动构造函数标记为显式默认将解决此问题:
class Foo {
public:
Foo() = default;
Foo(Foo const &) = delete;
Foo(Foo&&) = default;
};
您将获得一个带有默认移动构造函数的不可复制对象,在我看来,这些显式声明比隐式声明更好(例如,仅将移动构造函数声明为default
不删除复制构造函数)。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)