C++11 "Non-movable"型

C++11 "Non-movable" type

本文关键字:Non-movable C++11      更新时间:2023-10-16

可能重复:
为什么C++11被删除的函数会参与过载解决?

关于以下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++11main.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++11main.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.
  • 如果显式删除了move构造函数,编译器不应该使用copy构造函数吗
  • 有人知道"不可移动"类型的用法吗

提前谢谢。

A(A&&) = delete;

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

private: 
  A(A&&){}

事实上,在= delete可用之前,这就是其他操作员有时使用的技巧。同样,它存在于查找的意义上,但调用它是不允许的,在C++中,调用权限(在几乎或所有情况下(是在其他一切之后完成的,例如重载解析、名称查找。

标准实际上说(8.4.3(

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

还有一点(我发现(说,被删除的函数不应该参与名称查找。

此外,从8.4.3

一种隐式或显式引用已删除函数的程序,除了宣布它之外,它是不正规的。[注意:这包括打电话函数隐式或显式并形成指针或指向函数成员的指针。它甚至适用于可能未计算的表达式。

删除move构造函数时,它不会将其从通过名称查找找到的函数集中删除。每当您的代码正常使用move构造函数时,您都会收到一个错误,因为即使找到了它,它也已被删除。

你的代码中有两个动作。第一种是return a,因为当复制省略是可能的,并且要复制的对象由左值(此处为a(指定时,它被视为移动。第二个是分配A b = f(),因为f()为您提供了一个尚未绑定到引用的临时对象。

如果你想找到复制构造函数而不是删除的移动构造函数,你应该去掉删除的定义。

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

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

[注意:当移动构造函数没有隐式声明或显式提供时,原本会调用移动构造函数的表达式可能会调用复制构造函数。--end Note]

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

8.4.3已删除定义[dcl.fct.def.delete]

2隐式或显式引用已删除函数而不是声明该函数的程序是格式错误的。注意:这包括隐式或显式调用函数,并形成指向成员的指针或指针到函数。它甚至适用于表达式中未潜在求值的引用。如果函数是重载的,只有通过重载解析选择了函数时才会引用它。——结束语]

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

由于引用了已删除的move构造函数,因此程序格式不正确。

不可移动类型的"用法"可以是防止移动,从而防止返回本地对象。我自己还没有见过这样的用法,我也不知道这是否有意义,但YMMV。