显式移动构造函数
Explicit move constructor
尝试编译以下代码:
struct Foo
{
explicit Foo ( void ) { }
explicit Foo ( Foo&& rhs ) { }
};
Foo bar ( void )
{
return Foo();
}
得到以下错误:
调用隐式删除的"Foo"的复制构造函数
很明显,副本ctor被隐式删除了。
问题1:为什么编译器需要Foo
的副本ctor?我期望bar
的返回值是由具有move ctor的右值Foo()
构造的。
然后,我将move-ctor重新声明为隐式,所有内容都成功编译。
问题2:当我将move ctor重新声明为隐式时,为什么编译器不再需要copy ctor?
问题3:explicit
关键字在复制和移动运算符的上下文中意味着什么,因为它肯定意味着不同于常规运算符的上下文。
这是因为返回值被视为隐式转换。
引用C++11标准:
6.6.3返回语句
2[…]
带有非void类型表达式的return语句只能在返回值的函数中使用;表达式的值将返回给函数的调用方表达式的值将隐式转换为它所在函数的返回类型返回语句可能涉及临时对象的构建、复制或移动(12.2)。〔…〕
从返回表达式到保存返回值的临时对象的转换是隐式的。因此,正如这将导致错误一样
Foo f = Foo(); // Copy initialization, which means implicit conversion
以代码为例也会引发类似的情况。
问题1:为什么编译器需要Foo的副本ctor?我希望bar的返回值是由带有move ctor的右值Foo()构造的。
因为上述原因,Foo(Foo&&)
不是一个可行的过载。规则规定,无论何时不能使用移动构造函数,编译器都应该考虑复制构造函数,在您的情况下,由于存在用户定义的移动构造函数,复制构造函数被隐式删除。
问题2:当我将move ctor重新声明为隐式时,为什么编译器不再需要copy ctor?
这是因为你的move构造函数现在可以使用了。因此,编译器可以立即使用它,甚至不考虑复制构造函数的存在。
问题3:显式关键字在复制和移动运算符的上下文中意味着什么,因为它肯定意味着与常规运算符的上下文不同的东西。
IMHO,这没有意义,只会导致问题,就像你的情况一样。
bar
的返回类型为Foo
。没有复制构造函数,显式移动构造函数无法工作,因为仍然需要Foo&&
和Foo
之间的隐式转换。从这个意义上讲,explicit Foo(Foo&&)
与任何其他explicit
转换构造函数没有什么不同。从不同类型转换时仍然会出现此问题。这是使用int
:的类似示例
struct Foo
{
explicit Foo(int) {}
};
Foo bar ( void )
{
return 42; // error: could not convert '42' from 'int' to 'Foo'
}
Q1:因为没有其他东西可以使用。
Q2:因为它使用move构造函数从Foo&&
隐式转换为Foo
。
Q3:它与普通转换构造函数的含义相同。
这与C++中重载解析的工作方式有关。
过载解决的第一步是形成一组候选函数。第二步是将候选函数集缩小为可行函数集。第三步是选择唯一的最佳可行函数(如果有的话)。如果删除了最佳可行函数,那么程序就是格式错误的。
因为move构造函数被声明为explicit
,所以它不是从Foo()
隐式转换为函数返回类型的候选函数。唯一的候选函数是Foo::Foo(const Foo&)
,它是隐式声明的复制构造函数这是一个候选函数,即使它被声明为已删除。它是通过过载分辨率选择的,是唯一可行的功能;然后在尝试调用已删除的函数时出现错误。
如果您没有声明移动构造函数explicit
,那么移动构造函数和隐式声明的复制构造函数都是候选函数。在这种情况下,两者都是可行的。然而,move构造函数赢得了重载解析,因为相对于const左值引用,右值更喜欢绑定到右值引用。因此,move构造函数是最佳可行函数。在这种情况下,复制构造函数被删除并不重要,因为它在重载解析中丢失了。
tl;dr:
答案1:因为move构造函数不是转换的候选函数。
答案2:因为move构造函数是一个候选函数,并且赢得了重载解决方案。
答案3:不,意思是一样的。
- 为什么不调用移动构造函数?(默认情况下只有构造器,没有别的)
- std::vector::p ush_back() 不会在 MSVC 上编译具有已删除移动构造函数的对象
- 仅包含可移动 std::map 的类的移动构造函数不起作用
- 为什么调用复制构造函数而不是移动构造函数?
- 基类中的默认析构函数禁用子类中的移动构造函数(如果有成员)
- 从具有按值捕获的 lambda 移动构造 std::函数时,移动构造函数调用两次
- 具有已删除移动和复制构造函数的类的就地构造
- 移动构造函数和右值引用
- 使用移动调用对等构造函数unique_ptr默认构造函数
- 为什么 std::memmove 中联合的默认非平凡移动构造函数C++?
- 具有专用化的模板类中的可靠条件复制和移动构造函数
- 构造函数采用std::string_view与std::string并移动
- C++:为什么不调用移动构造函数?
- 了解构造函数在移动、复制、赋值语义中的行为
- 没有移动的构造函数移动课程
- 引用绑定和复制构造函数/移动构造函数
- 构造函数移动
- C++ 向量实现 - 移动构造函数 - 移动与前进
- 我真的必须取消移动构造函数/移动结构中的所有成员还是只是指针
- 将类(没有默认构造函数)移动到另一个类的move构造函数中