C ++ 11“不可移动”类型

时间:2012-12-29 20:16:54

标签: c++ gcc c++11 clang move-semantics

  

可能重复:
  Why do C++11-deleted functions participate in overload resolution?

我对以下C ++ 11代码有两个问题:

#include <iostream>

using namespace std;

struct A {
  A()  { cout << "Default c-tor" << endl; }
  A(const A&)  { cout << "Copy c-tor" << endl; }
  A(A&&) = delete;
};

A f()
{
 A a;
 return a;
}

int main()
{
  A b = f();
  return 0;
}

我使用gcc和clang

得到以下编译错误

gcc-4.7.2(g ++ --std = c ++ 11 main.cpp):

main.cpp: In function ‘A f()’:
main.cpp:16:9: error: use of deleted function ‘A::A(A&&)’
main.cpp:8:2: error: declared here
main.cpp: In function ‘int main()’:
main.cpp:21:10: error: use of deleted function ‘A::A(A&&)’
main.cpp:8:2: error: declared here

clang-3.0(clang ++ --std = c ++ 11 main.cpp):

main.cpp:19:4: error: call to deleted constructor of 'A'
        A b = f();
          ^   ~~~
main.cpp:8:2: note: function has been explicitly marked deleted here
        A(A&&) = delete;
        ^
1 error generated.
  • 如果显式删除了移动构造函数,编译器是否应该使用复制构造函数?
  • 有没有人知道“不可移动”类型的用途?

提前致谢。

4 个答案:

答案 0 :(得分:6)

A(A&&) = delete;

将其声明并定义为delete仍然会声明它,并且不会使它完全不存在。相反,将类似(但不完全相同)声明为空和私有。像这样:

private: 
  A(A&&){}

事实上,这是= delete可用之前有时用于其他运营商的技巧。 同样,它存在于查找的意义上,但调用它是不允许的,并且在C ++调用权限(几乎或所有情况下)都在其他所有事情之后完成,例如重载解析,名称查找。

标准实际上说(8.4.3)

  

删除的函数是隐式内联的。

并且(我发现)说删除的函数不应该参与名称查找。

另外,从8.4.3开始

  

隐式或明确引用已删除函数的程序,   除了宣布它之外,是不正确的。 [注意:这包括打电话   函数隐式或显式并形成指针或   指向函数的指针成员。它甚至适用于参考   无法评估的表达式。

答案 1 :(得分:2)

这是一项研究任务,但我认为声明移动构造函数表明要考虑移动构造函数。然后当它获得delete d时,这意味着如果有移动构造函数,则可以移动对象移动到的位置。如果你想要一个没有被移动但被复制的对象,你只需要声明一个复制构造函数,你就不会提到移动构造函数。

我还没有在标准中找到声明,但是,它明确说明了上述内容,但在12.8 [class.copy]第9段中有注释支持部分上述声明:

  

[注意:当未隐式声明或显式提供移动构造函数时,否则将调用移动构造函数的表达式可能会调用复制构造函数。 - 后注]

答案 2 :(得分:2)

删除移动构造函数时,它不会从名称查找找到的函数集中删除它。每当您的代码通常使用移动构造函数时,您将收到错误,因为即使找到它,它也会被删除。

您的代码中有两个动作。第一个是return a,因为当可以进行复制省略并且复制的对象由左值(a,这里)指定时,它被视为移动。第二个是作业A b = f(),因为f()给你一个尚未绑定参考的临时文件。

如果您希望找到复制构造函数而不是删除的移动构造函数,那么您应该删除已删除的定义。

答案 3 :(得分:1)

来自C ++工作草案2012-11-02

  

8.4.3删除的定义[dcl.fct.def.delete]
  ...
  2除了声明它之外,隐式或显式引用已删除函数的程序是不正确的。 [注意:这包括隐式或显式调用函数并形成指针或指向成员的指针   到功能。它甚至适用于未进行潜在评估的表达式中的引用。如果一个功能   重载,只有在通过重载决策选择函数时才会引用它。 - 结束说明]
  ...
  4删除的函数是隐式内联的。

由于引用了已删除的移动构造函数,因此该程序格式错误。

不可移动类型的“用法”可能是为了防止移动,因此阻止返回本地对象。我自己没有见过这样的用法,我不知道这是否有意义,但是YMMV。