我正在使用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的预期用法,这个例子是设计的。只是希望能更好地掌握这种新类型的行为。
答案 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)
查看代码中发生的事情:
CreateA()
被称为A
类型的局部变量。A
类型的对象超出范围并被销毁a2
初始化为函数调用中一次对象的副本而且......那是行不通的。你想要复制的对象已经消失了。未定义的行为。
不要那样做。 :)
在C ++中,引用不会影响引用对象的生命周期。没有“我指着这个物体,所以你不能破坏它!”。
永远不要返回对本地对象的引用。它不起作用,所以...就是不要这样做。