为什么要自动v {create()};不编译?

时间:2012-11-07 08:57:24

标签: c++ visual-c++ c++11 visual-studio-2012 move

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

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”副本。 最好

2 个答案:

答案 0 :(得分:6)

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

要使x成为A,您有两个选择:

  1. 请勿在此处使用auto

    A x{ create() };
    
  2. 请勿在此处使用统一初始化:

    auto x(create());
    
  3. 除此之外,我还会在您的代码中看到其他两个问题。首先,正确的拷贝构造函数的签名应如下所示:

    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”。根据您想要操作的抽象级别,它是“移动的CTOR”或“移动参考的CTOR”。通用引用始终是关于模板和特定类型类型的推导。

    还请阅读Scott Meyers的一篇文章,我附在另一条评论http://scottmeyers.blogspot.com/2012/10/copying-constructors-in-c11.html中,您在笔记中提到的同一位C ++专家正好解释了您所面临的问题。希望有所帮助。

答案 1 :(得分:1)

该行

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

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

如果你写

A x{ create() };

代码编译,x的类型为A


我不会从A&&返回create(),请参阅Move Semantics and Compiler Optimizations。我也没有在斯科特的幻灯片中看到这一点。


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

#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不是摆脱不必要副本的唯一方法。编译器可以为您执行此操作,例如,请参阅What are copy elision and return value optimization?Copy elision