返回一个引用有没有好主意? [英] Is returning a reference ever a good idea?
问题描述
我们都知道返回对局部变量的引用是一个坏主意
We all know that returning a reference to a local variable is a bad idea. However, I'm wondering if it's ever really a good idea to a return a reference at all and if it's possible to determine some good rules about when or when not to do it.
我返回一个引用的问题是调用函数需要关心一个对象的生命周期,这不应该是它的责任。作为一个假设的例子:
My problem with returning a reference is that the calling function needs to care about the lifetime of an object that shouldn't be its responsibility. As a contrived example:
#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;
}
这里,向量
在 foo
结束时超出范围,破坏其内容并使对其元素的任何引用无效。 vector :: operator []
返回对元素的引用,因此当此引用进一步返回 foo
, main
中的引用是悬空。我不相信const引用会延长这里的生命期,因为它不是一个临时的引用。
Here, the vector
goes out of scope at the end of foo
, destroying its contents and invalidating any references to its elements. vector::operator[]
returns a reference to the element, and so when this reference is further returned out of foo
, the reference in main
is dangling. I don't believe the const reference will extend the lifetime here because it's not a reference to a temporary.
正如我所说,这是一个假设的例子,作家 foo
可能不会这么愚蠢地尝试并返回 v [0]
作为参考。然而,很容易看到返回引用需要调用者关心它不拥有的对象的生命周期。将元素推送到向量
中复制它,所以然后向量
负责它。这个问题不存在用于传递引用参数,因为您知道函数将在调用程序继续并销毁对象之前完成。
As I said, this is a contrived example and the writer of foo
probably wouldn't be so silly to try and return v[0]
as a reference. However, it's easy to see how returning a reference requires the caller to care about the lifetime of an object it doesn't own. Pushing an element into a vector
copies it, so then the vector
is responsible for it. This problem doesn't exist for passing a reference argument because you know the function will complete before the caller continues and destroys the object.
我可以看到返回引用允许一些很好的类似数组的语法,如 v [0] = 5
- 但是有一个成功函数,如 v.set(index,value )
?至少用这个我们不会暴露内部对象。我知道返回引用可能会提高性能,但通过 RVO ,命名为RVO( NRVO),并且移动语义是可忽略的或不存在的。
I can see that returning a reference allows some nice array-like syntax like v[0] = 5
- but what's so bad about having a member function like v.set(index, value)
? At least with this we wouldn't be exposing the internal objects. I know there may also be a performance increase from returning a reference, but with RVO, Named RVO (NRVO), and move semantics it is either negligible or non-existent.
所以我一直在想象返回一个引用的情况是真正安全的,但是我不能让我的头围绕着所有可能涉及的所有权语义的所有不同排列。
So I've been trying to imagine under which situations returning a reference is ever truly safe, but I can't get my head around all the different permutations of ownership semantics that it might involve. Are there any good rules on when to do this?
注意:我知道一个更好的方法来处理向量中的所有权$ c $
Note: I know a better way to deal with ownership in vector
s is to use smart pointers, but then you get the same problem with a different object - who owns the smart pointer?
推荐答案
struct Goo
{
int & operator[](size_t i) { return arr[i]; }
int & front() { return arr[0]; }
// etc.
private:
int * arr;
};
另一个用例是当你返回一个被传入的东西的引用。典型的例子是<
:
Another use case is when you return a reference to a thing that was passed in. The typical example is a chainable operation like <<
:
std::ostream & operator<<(std::ostream & os, Goo const & g)
{
return os << g[3];
}
最后一个例子,这里有一个线程安全的全局对象:
As a final example, here's a thread-safe global object:
Goo & get_the_object()
{
static Goo impl;
return impl;
}
引用是语言的一个组成部分,一个函数调用。正如你所说,理解对象的生命周期很重要,但这始终是真的,而不是返回引用的特殊问题。
References are an integral part of the language, and they may well be returned by a function call. As you said, it's important to understand the lifetime of objects, but that's always true and not a particular problem of returning references.
这篇关于返回一个引用有没有好主意?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!