显式移动构造函数

时间:2014-02-19 06:40:19

标签: c++ c++11 constructor move-constructor c++14

尝试编译以下代码:

struct Foo
{
    explicit Foo ( void ) { }
    explicit Foo ( Foo&& rhs ) { }
};

Foo bar ( void )
{
    return Foo();
}

收到以下错误:

  

调用隐式删除的'Foo'

复制构造函数

嗯,很明显,拷贝代码被隐式删除了。

问题1:为什么编译器需要Foo的copy-ctor?我希望bar的返回值可以使用move-ctor从右值Foo()构建。

然后我将move-ctor重新声明为隐式,并且所有内容都成功编译。

问题2:当我将move-ctor重新声明为隐式时,为什么编译器不再需要copy-ctor?

问题3: explicit关键字在复制和移动ctors的上下文中意味着什么,因为它肯定意味着与常规ctors的上下文不同。

3 个答案:

答案 0 :(得分:10)

这是因为返回一个值被视为implicit conversion

引用C ++ 11标准:

  

6.6.3退货声明

     

2 [...]

     

表达式为非void类型的return语句只能在返回值的函数中使用;表达式的值返回给函数的调用者。 表达式的值被隐式转换为它出现的函数的返回类型。 return语句可能涉及构造和复制或移动临时对象(12.2)。 [...]

从返回表达式到临时对象的转换以保存返回值是隐式的。因此,这会导致错误

Foo f = Foo();   // Copy initialization, which means implicit conversion
以代码为例,也会触发类似的代码。


  

问题1:为什么编译器需要Foo的copy-ctor?我期望使用move-ctor从rvalue Foo()构造bar的返回值。

因为上述原因,Foo(Foo&&)不是可行的超载。规则规定,无论何时移动构造函数都不能使用,编译器应该考虑复制构造函数,在您的情况下,由于存在用户定义的移动构造函数,它会被隐式删除。

  

问题2:当我将move-ctor重新声明为隐式时,为什么编译器不再需要copy-ctor?

这是因为您的移动构造函数现在可以使用了。因此,编译器可以立即使用它,甚至不用考虑是否存在复制构造函数。

  

问题3:显式关键字在复制和移动ctors的上下文中意味着什么,因为它肯定意味着与常规ctors的上下文不同。

恕我直言,这没有任何意义,只会导致问题,就像你的情况一样。

答案 1 :(得分:6)

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 :因为它使用移动构造函数隐式地从Foo&&转换为Foo

Q3 :它与普通转换构造函数的含义相同。

答案 2 :(得分:2)

这与过载解析在C ++中的工作原理有关。

重载解析的第一步是形成一组候选函数。第二步是将候选函数集缩小为一组可行函数。第三步是选择唯一的最佳可行功能(如果有)。如果删除最佳可行功能,则该程序格式不正确。

因为移动构造函数被声明为explicit,所以不是候选函数,用于将Foo()隐式转换为函数的返回类型。唯一的候选函数是Foo::Foo(const Foo&),隐式声明的复制构造函数。 这是候选功能,即使它被声明为已删除。它是通过重载分辨率选择的,是唯一可行的功能;然后在尝试调用已删除的函数时出错。

如果你没有声明移动构造函数explicit,那么两者移动构造函数和隐式声明的复制构造函数都是候选函数。在这种情况下,两者都是可行的。但是,移动构造函数会获得重载解析,因为rvalues更喜欢通过const左值引用绑定到rvalue引用。因此,移动构造函数是最可行的函数。在这种情况下,复制构造函数被删除并不重要,因为它会在重载决策中丢失。

TL; DR:

回答1 :因为移动构造函数不是转换的候选函数

回答2 :因为移动构造函数是候选函数,并且赢得重载解析。

回答3 :不,这意味着同样的事情。