我们都知道 returning a reference to a local variable is a bad idea .但是,我想知道返回引用是否真的是个好主意,是否有可能确定一些关于何时或何时不返回引用的好规则。
我关于返回引用的问题是调用函数需要关心对象的生命周期,而这不应该是它的责任。作为一个人为的例子:
#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
返回时,main
中的引用悬空。我不相信 const 引用会延长此处的生命周期,因为它不是对临时对象的引用。
正如我所说,这是一个人为的例子,foo
的作者可能不会那么愚蠢地尝试返回 v[0]
作为引用。但是,很容易看出返回引用如何要求调用者关心它不拥有的对象的生命周期。将元素插入 vector
会复制它,因此 vector
负责它。传递引用参数时不存在此问题,因为您知道函数将在调用者继续并销毁对象之前完成。
我可以看到返回一个引用允许一些很好的类似数组的语法,比如 v[0] = 5
- 但是拥有一个像 v.set(index , 值)
?至少这样我们就不会暴露内部对象。我知道返回引用也可能会提高性能,但是使用 RVO , 命名为 RVO (NRVO),并且移动语义它要么可以忽略不计,要么不存在。
所以我一直在尝试想象在哪些情况下返回引用是真正安全的,但我无法理解它可能涉及的所有权语义的所有不同排列。关于何时执行此操作是否有任何好的规则?
注意:我知道处理 vector
中的所有权的更好方法是使用智能指针,但是你会在使用不同的对象时遇到同样的问题 - 谁拥有智能指针?
最佳答案
返回引用有很多好的用途。正如您所说,一种是模拟类似于 native 取消引用运算符的东西:
struct Goo
{
int & operator[](size_t i) { return arr[i]; }
int & front() { return arr[0]; }
// etc.
private:
int * arr;
};
另一个用例是当您返回对传入的事物的引用时。典型的例子是像 <<
这样的可链接操作。 :
std::ostream & operator<<(std::ostream & os, Goo const & g)
{
return os << g[3];
}
作为最后一个例子,这是一个线程安全的全局对象:
Goo & get_the_object()
{
static Goo impl;
return impl;
}
引用是语言不可或缺的一部分,它们很可能由函数调用返回。正如您所说,了解对象的生命周期很重要,但这始终是正确的,而不是返回引用的特定问题。
关于c++ - 返回引用是个好主意吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13077979/