7

有人可以验证以下是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个元素被复制之前就被扔掉了?

4

2 回答 2

11

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

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

于 2013-03-14T13:42:25.973 回答
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;

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


对于你的第二个问题:

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

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

是的,这是另一种可能的解决方案。f()[0]将访问临时副本的第一个元素并使用其值来初始化myIntCopy变量。保证v返回的副本f()至少在整个表达式执行之前存在,请参阅C++03 Standard 12.2 Temporary objects §3

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

于 2013-03-14T13:46:16.093 回答