我正在对移动语义进行一些测试,我尝试了这个:
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”副本。 最好
答案 0 :(得分:6)
auto
的大括号将始终以std::initializer_list<T>
类型结尾。所以基本上你在这里尝试为std::initializer_list<A>
而不是x
创建一个A
,这可能是你的意图。但是,您的代码应该编译正常,这可能是VS最新CTP编译器中的错误。
要使x
成为A
,您有两个选择:
请勿在此处使用auto
:
A x{ create() };
请勿在此处使用统一初始化:
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”。根据您想要操作的抽象级别,它是“移动的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。