引用C ++中函数返回的向量元素

时间:2013-03-14 13:39:51

标签: c++ memory-management reference return return-by-value

有人可以验证以下是BUG,并解释原因吗?我想我知道,但我不清楚细节。 (我的实际问题涉及枚举的向量,而不是整数,但我认为它不重要。)假设我有以下代码:

std::vector<int> f (void) {
  std::vector<int> v;
  v.push_back(5);
  return v;
}

void g (void) {
  const int &myIntRef = f()[0];
  std::cout << myIntRef << std::endl;
}

我是否正确myIntRef是一个悬空引用,因为f的返回值在堆栈中无处保存?

此外,以下是有效修复,还是仍然是错误?

  const int myIntCopy = f()[0];  // copy, not a reference

换句话说,f()的返回结果是否可以在复制第0个元素之前抛弃?

2 个答案:

答案 0 :(得分:11)

这是一个错误。在完整表达式const int &myIntRef = f()[0];的末尾,临时向量将被销毁并释放内存。以后使用myIntRef是未定义的行为。

在某些情况下,绑定对临时的引用可以延长临时的生命周期。这不是这种情况之一,编译器不知道std::vector<int>::operator[]返回的引用是临时的一部分还是对具有静态存储持续时间的int的引用或其他任何东西,它赢了不会延长寿命。

答案 1 :(得分:2)

是的,确实做错了。当你打电话:

return v;

正在创建对象v的临时副本并且

const int &myIntRef = f()[0];

使用此临时副本的第一个元素初始化您的引用。在此行之后,临时副本不再存在,这意味着myIntRef是无效引用,使用该引用会产生未定义的行为

你应该做的是:

std::vector<int> myVector = f();
const int &myIntRef = myVector[0];
std::cout << myIntRef << std::endl;

(感谢 copy elision )使用赋值运算符通过使用myVector初始化v对象而不创建v的副本。在这种情况下,引用的生命周期等于myVector对象的生命周期,使其成为完全有效的代码。


关于你的第二个问题:

  

“此外,以下是有效的修复,还是它仍然是一个错误?”

 const int myIntCopy = f()[0];  // copy, not a reference

是的,这是另一种可能的解决方案。 f()[0]将访问临时副本的第一个元素,并使用其值初始化myIntCopy变量。保证v返回的f()副本至少存在,直到整个表达式执行为止,参见 C ++ 03标准12.2临时对象§3

  

临时对象在评估全表达式(1.9)的最后一步时被销毁,该表达式(词法上)包含创建它们的点。