将rvalue-reference绑定到VC ++中的局部变量

时间:2012-12-21 16:15:57

标签: c++ visual-c++ rvalue-reference

我正在使用VC ++ 2012运行以下代码:

#include <utility>

struct A
{
    int* m_p;

    A() { m_p = new int; }
    ~A() { delete m_p;  }

    A(const A& otherA)
    {
        m_p = new int;

        // BOOM!
        *m_p = *otherA.m_p;
    }
};

A&& CreateA()
{
    A a;
    return std::move(a);
}

int _tmain(int argc, _TCHAR* argv[])
{
    A a2 = CreateA();
    return 0;
}

在创建a2 A期间,复制ctor被调用 - 并且崩溃,因为在CreateA()中创建的源对象已经被销毁。 这是标准行为吗?这可能是编译器错误吗?

请注意,如果将a2的类型从“A”更改为“const A&amp;”崩溃不会发生 - 这加剧了人们对它确实是一个错误的怀疑。 任何人都可以对此有所了解吗?

注意:我完全清楚这不是rvalue-refs的预期用法,这个例子是设计的。只是希望能更好地掌握这种新类型的行为。

2 个答案:

答案 0 :(得分:2)

You cannot access a local variable outside its scope。 Rvalue引用不会改变它们:它们仍然是引用。提供的代码具有未定义的行为,因为它返回对局部变量的引用,然后访问它。

不要返回右值引用。绝大部分时间都是愚蠢的。改为返回值:

A CreateA()
{
    A a;
    return a; // a move here is automatic
              // unless you are using a compiler with outdated rules like MSVC
    //return std::move(a); // ok, poor MSVC
    // alternatively:
    //return A{}; //or 
    //return A();
}

当您编写A const& a2 = CreateA();时,没有任何内容崩溃,因为您实际上并未访问任何对象。你要做的只是抓住一个悬垂的参考。但是,这个代码甚至没有格式良好,它只是编译,因为MSVC有一些参考绑定的过时规则。

因此,基本上,这些行为是编译器错误和未定义行为的混合:)

答案 1 :(得分:2)

查看代码中发生的事情:

  1. CreateA()被称为
  2. 在函数内部,创建了A类型的局部变量。
  3. 您创建一个指向此局部变量的右值引用
  4. 您返回此左值参考
  5. 当你返回时,右值引用所指向的A类型的对象超出范围并被销毁
  6. 引用现在指向一个被破坏的对象
  7. 您尝试将a2初始化为函数调用中一次对象的副本
  8. 而且......那是行不通的。你想要复制的对象已经消失了。未定义的行为。

    不要那样做。 :)

    在C ++中,引用不会影响引用对象的生命周期。没有“我指着这个物体,所以你不能破坏它!”。

    永远不要返回对本地对象的引用。它不起作用,所以...就是不要这样做。