Jos*_*eld 1 c++ reference ownership
我们都知道返回对局部变量的引用是个坏主意.但是,我想知道返回引用是否真的是一个好主意,如果有可能确定何时或何时不执行它的一些好规则.
返回引用的问题在于调用函数需要关心不应该负责的对象的生命周期.作为一个人为的例子:
#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;
}
Run Code Online (Sandbox Code Playgroud)
这里,vector超出范围foo,破坏其内容并使对其元素的任何引用无效.vector::operator[]返回对元素的引用,因此当进一步返回此引用时foo,引用处于main悬空状态.我不相信const引用会延长这里的生命周期,因为它不是对临时引用的引用.
正如我所说,这是一个人为的例子,作者foo可能不会那么愚蠢地试图v[0]作为参考.但是,很容易看出返回引用如何要求调用者关心它不拥有的对象的生命周期.将元素推送到vector副本中,然后由vector它负责.传递引用参数不存在此问题,因为您知道函数将在调用者继续并销毁对象之前完成.
我可以看到返回一个引用允许一些很好的类似数组的语法v[0] = 5- 但是有一个成员函数是什么样的糟糕v.set(index, value)?至少我们不会暴露内部对象.我知道返回引用可能会有性能提升,但是对于RVO,命名RVO(NRVO)和移动语义,它可以忽略不计或不存在.
所以我一直试图想象在什么情况下返回引用是真正安全的,但我无法理解它可能涉及的所有权语义的所有不同排列.何时这样做有什么好的规则?
注意:我知道更好的方法来处理vectors中的所有权是使用智能指针,但是你会遇到一个不同的对象 - 谁拥有智能指针?
Ker*_* SB 10
返回引用有很多好的用途.正如你所说的那样,就像模仿本地解除引用运算符一样:
struct Goo
{
int & operator[](size_t i) { return arr[i]; }
int & front() { return arr[0]; }
// etc.
private:
int * arr;
};
Run Code Online (Sandbox Code Playgroud)
另一个用例是当你返回对传入的东西的引用时.典型的例子是一个可链接的操作,如<<:
std::ostream & operator<<(std::ostream & os, Goo const & g)
{
return os << g[3];
}
Run Code Online (Sandbox Code Playgroud)
作为最后一个例子,这是一个线程安全的全局对象:
Goo & get_the_object()
{
static Goo impl;
return impl;
}
Run Code Online (Sandbox Code Playgroud)
引用是语言的组成部分,它们很可能通过函数调用返回.正如您所说,理解对象的生命周期很重要,但这始终是正确的,而不是返回引用的特定问题.