我们都知道返回对局部变量的引用是个坏主意。但是,我想知道返回引用是否真的是一个好主意,以及是否有可能确定一些关于何时或何时不这样做的好规则。
我返回引用的问题是调用函数需要关心对象的生命周期,这不应该是它的责任。作为一个人为的例子:
#include <vector>
const int& foo() {
std::vector<int> v = {1, 2, 3, 4, 5};
return v[0];
}
int main(int argc, const char* argv[])
{
const int& not_valid = foo();
return 0;
}
在这里,vector
末尾的 超出范围foo
,破坏其内容并使对其元素的任何引用无效。vector::operator[]
返回对元素的引用,因此当进一步从 中返回此引用时foo
,引用 inmain
悬空。我不相信 const 引用会延长这里的生命周期,因为它不是对临时的引用。
正如我所说,这是一个人为的例子,作者foo
可能不会那么愚蠢地尝试返回v[0]
作为参考。但是,很容易看出返回引用如何要求调用者关心它不拥有的对象的生命周期。将一个元素推入一个vector
副本中,然后由vector
它负责。传递引用参数不存在此问题,因为您知道函数将在调用者继续并销毁对象之前完成。
我可以看到返回引用允许一些不错的类似数组的语法v[0] = 5
- 但是拥有这样的成员函数有什么不好v.set(index, value)
?至少这样我们就不会暴露内部对象。我知道返回引用也可能会提高性能,但是对于RVO、命名 RVO (NRVO) 和移动语义,它要么可以忽略不计,要么不存在。
所以我一直试图想象在哪些情况下返回引用是真正安全的,但我无法理解它可能涉及的所有不同的所有权语义排列。关于何时执行此操作有什么好的规则吗?
注意:我知道在 s 中处理所有权的更好方法vector
是使用智能指针,但是使用不同的对象会遇到同样的问题——谁拥有智能指针?