函数返回的临时对象不总是r值吗?

时间:2012-05-18 16:59:30

标签: c++ rvalue-reference temporary-objects

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值?

这是编译器的错误,还是我的理解错误?

5 个答案:

答案 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;
}

现在你正在返回一个匿名临时 - 线索是创建一个临时的并按值返回它而不将它绑定到名称。

正如其他人正确指出的那样,你正在做的是返回一个指向静态(非临时)命名(非匿名)对象的指针。 指针可能是一个匿名临时用户,但指向的东西不是。