c++ - 返回引用是个好主意吗?

标签 c++ reference ownership

我们都知道 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;
}

此处,vectorfoo 的末尾超出范围,破坏其内容并使对其元素的任何引用无效。 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/

相关文章:

c++ - 为什么用函数构造不会导致内存泄漏?

python - 在 python 中模拟一个 int

mysql - 更改 MySQL 存储过程的所有者?

c++ - 排列中的升序子序列

c++ - clang-format:如何对齐结构初始化列表

c++ - 一般来说,当它们共享同一个父类时,是否有办法从另一个子类访问子类?

C++11 自动 : what if it gets a constant reference?

使用 Tkinter 标签更改文本的 Python 引用

rust - 为什么分配时会得到 "temporary value dropped while borrowed",但通过函数传递时却不会?

rust - 如何在 Rust 中使用 BigInt 和 Bigint 生成一系列值?