1

我正在对移动语义进行一些测试,我尝试了这个:

class A{
public:
    A(){printf("A CTOR\n");}
    A(A&) {printf("A CTOR by copy\n");}
    A(A&&){printf("A CTOR by universal reverence\n");}
};

A&& create(){
    A v;
    return std::move(v);
}

auto x{ create() };//this does not compile

float d[]{1.2,1.3,5,6};//this does compile

我收到以下错误:

error C3086: cannot find 'std::initializer_list': you need to #include <initializer_list>

我不明白,因为初始化列表功能已通过 CTP2012 nov. 添加到 VC11 中。这是因为我们必须等待 stdlib 的更新吗?

我认为代码是正确的,因为我从 Scott meyers 的幻灯片中复制了它:Move Semantics, Rvalue References, Perfect Forwarding

感谢您的帮助。 供您参考,出现虚假副本是因为我没有在我的 CTOR 中逐个添加“const”。 最好的

4

2 回答 2

6

大括号auto总是以std::initializer_list<T>类型结束。所以基本上这里发生的事情你尝试在std::initializer_list<A>这里创建一个x而不是A你在这里的意图。但是,您的代码应该可以正常编译,这可能是 VS 最新 CTP 编译器中的一个错误。

要成为xA有两个选择:

  1. 不要auto在这里使用:

    A x{ create() };
    
  2. 不要在这里使用统一初始化:

    auto x(create());
    

除此之外,我在您的代码中看到了另外两个问题。首先正确复制构造函数的签名应该如下所示:

A(const A &) {printf("A CTOR by copy\n");}

此外,不鼓励从函数返回 RValue 引用。相反,您应该像这样按值返回:

A create(){
  A v;
  return v;   // std::move not needed here because C++11 compiler will put it for you here
}

要不就:

A create(){
  return A();
}

编辑:

哦,政治正确A(A&&) 并不是“普遍参考的 CTOR”。它是“A CTOR by move”或“A CTOR by rvalue reference”,具体取决于您要操作的抽象级别。通用引用总是关于模板和特定类型的类型推导。

另请阅读我在另一条评论中附加的 Scott Meyers 的一篇文章http://scottmeyers.blogspot.com/2012/10/copying-constructors-in-c11.html您在笔记中提到的同一位 C++ 大师准确地解释了你面临的问题。希望有帮助。

于 2012-11-07T09:37:02.350 回答
1

线

auto x{ create() };//this does not compile

创建一个initializer_list而不是 的实例A,例如参见std::initializer_list

如果你写

A x{ create() };

代码编译并且类型x将是A.


我不会返回A&&create()请参阅移动语义和编译器优化。我也没有在 Scott 的幻灯片中看到这一点。


以下代码仅打印A CTOR,请参见此处这是你能得到的最好的:必须创建对象。除此之外,没有不必要的复制构造函数或赋值运算符调用。

#include <cstdio>
#include <utility>
using namespace std;

class A{
public:
    A(){         printf("A CTOR\n");}
    A(const A&) {printf("A CTOR by copy\n");}
    A(A&&){      printf("A CTOR by universal reverence\n");}
    A& operator=(const A& ) = delete;
};

A create(){
    return A();
}

int main() {
    A x{ create() };
    return 0;
}

std::move 不是摆脱不必要副本的唯一方法。编译器可以为你做,例如看什么是复制省略和返回值优化?复制省略

于 2012-11-07T09:34:25.733 回答