struct Test
{
Test()
{}
Test(const Test& other)
{
cout << "Copy" << endl;
}
Test(Test&& other)
{
cout << "Move" << endl;
}
};
Test* f()
{
static Test t;
return &t;
}
int main()
{
auto t = *f();
return 0;
}
输出为:复制
*f()
显然是一个匿名临时对象,因此它应该是一个r值,并且应该调用move-constructor。为什么编译器将*f()
视为l值?
这是编译器的错误,还是我的理解错误?
答案 0 :(得分:14)
f()
的结果是Test*
类型的匿名临时对象。 f()
is an rvalue
*f()
通过所述指针执行间接寻址。与使用间接运算符的情况一样,结果是左值。
答案 1 :(得分:8)
为什么编译器将* f()视为l值?
因为 是一个l值。当应用于指针时,运算符*的结果是总是一个l值。并且你不能隐含地从l值移动。
记住带有动作的黄金法则:只有当保证安全时才会发生移动(对于“保证”的特定定义)。
看看你的代码。您想要移动的物体是否会被摧毁并且移动后无法进入?如果没有,那么必须使用std::move
从中移动;这告诉系统你要对由于移动而发生的任何搞砸负责。
答案 2 :(得分:3)
实际上,f()
的返回是一个指针。取消引用指针不会导致新对象重新出现。但是,您正在复制发生在返回值指向t
的内存地址的任何内容。在这种情况下,我当然希望得到一份副本。
答案 3 :(得分:1)
“* f()显然是一个匿名临时对象......”
不,不是!这是一个静态对象。
答案 4 :(得分:0)
Test f()
{
return Test();
}
int main()
{
auto t = f();
return 0;
}
现在你正在返回一个匿名临时 - 线索是创建一个临时的并按值返回它而不将它绑定到名称。
正如其他人正确指出的那样,你正在做的是返回一个指向静态(非临时)命名(非匿名)对象的指针。 指针可能是一个匿名临时用户,但指向的东西不是。