问题 C ++ 11“不可移动”类型[重复]


可能重复:
为什么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 ++ 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.
  • 如果显式删除了移动构造函数,编译器是否应该使用复制构造函数?
  • 有没有人知道“不可移动”类型的用途?

提前致谢。


9369
2017-12-29 20:16


起源

stackoverflow.com/questions/14085620/... - paulm
我想知道如果返回本地对象将如何 A(A&&) 被删除。 - Nawaz
实际上这是我的第一个问题,当显式删除移动构造函数时,编译器是否应该选择复制构造函数而不是移动构造函数? (我理解删除的函数在重载决策中被考虑的事实) - lucasmrod


答案:


A(A&&) = delete;

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

private: 
  A(A&&){}

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

标准实际上说(8.4.3)

删除的函数隐式内联。

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

另外,从8.4.3开始

隐式或显式引用已删除函数的程序,   除了申报之外,还有不良形式。 [注意:这包括打电话   函数隐式或显式并形成指针或   指向函数的指针成员。它甚至适用于参考   没有潜在评估的表达式。


6
2017-12-29 20:21



@Nawaz:它与其他两个答案相同,因为如果它真的“不存在”那么就不会在重载决策中考虑它。 Ofc我不会超过标准来引入与“英语”含义相矛盾的“存在”的技术定义;-)它被考虑用于某些目的而不是其他目的,尽管它没有函数体,因此它与定义的私有函数不同以上。 - Steve Jessop
@SteveJessop:通过存在,约翰意味着一些不真实的东西。他试图通过显示等效代码来解释他的意思:他 定义 它在私人部分。 - Nawaz
@Nawaz:耸耸肩。当然我不知道Johan的想法是什么,但我很确定它和其他两个回答者一样。 - Steve Jessop
@JohanLundberg:如果 deleted move-constructor意味着它在。中定义 private 意味着,类的成员函数将使用它,这是不正确的。因此,这不是等同的,并不意味着它 private。如果你离开了 未定义 (仅在私有部分中声明),那么它将接近等效代码,但即使如此,它也不是 究竟 当量。 - Nawaz
@Nawaz:当然,约翰从未说过它是等同的。 Tbh我不确定与私有构造函数的比较是否富有成效。它是该技术的替代品,但它的工作方式有所不同。但我同意它是相似的。 - Steve Jessop


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

您的代码中有两个动作。第一个是你的时候 return a 因为当可以进行复制时,可以复制的对象由左值指定(a,这里),它被视为一个举动。第二个是作业 A b = f()因为一个 f() 给你一个尚未被引用约束的临时。

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


2
2017-12-29 20:23





这是一项研究任务,但我 认为 声明移动构造函数表明要考虑移动构造函数。什么时候得到 deleted,这意味着如果有移动构造函数,可以将对象移动到可以移动的位置。如果你想要一个未被移动但被复制的对象,你只需要声明一个复制构造函数,你就不会提到移动构造函数。

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

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


2
2017-12-29 20:21





来自C ++ Working Draft 2012-11-02

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

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

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


1
2017-12-29 20:47