C++ 返回推荐信是个好主意吗?

C++ 返回推荐信是个好主意吗?,c++,reference,ownership,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 cha

我们都知道这一点。然而,我想知道返回一个引用是否真的是一个好主意,是否有可能确定一些关于何时或何时不这样做的好规则

我在返回引用时遇到的问题是,调用函数需要关心对象的生命周期,而这不应该是它的责任。作为一个人为的例子:

#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引用会延长这里的生命周期,因为它不是对临时的引用

正如我所说,这是一个人为的例子,foo的作者可能不会傻到试图返回v[0]作为引用。然而,很容易看出返回引用如何要求调用方关心它不拥有的对象的生存期。将一个元素推到一个向量中会复制它,因此向量对它负责。传递引用参数时不存在此问题,因为您知道函数将在调用方继续并销毁对象之前完成

我可以看到,返回一个引用允许一些类似数组的语法,比如v[0]=5——但是有一个像v.setindex,value这样的成员函数有什么不好呢?至少这样我们就不会暴露内部对象了。我知道返回一个引用也可能会提高性能,但是使用名为RVO NRVO和move语义,它要么可以忽略,要么根本不存在

所以我一直在尝试想象在什么情况下返回一个引用是真正安全的,但我无法理解它可能涉及的所有不同的所有权语义排列。什么时候做这件事有什么好的规定吗


注意:我知道处理向量所有权的更好方法是使用智能指针,但在不同的对象上也会遇到同样的问题-谁拥有智能指针?

返回引用有很多很好的用途。一个是,如您所说,模拟本机解引用操作符:

struct Goo
{
    int & operator[](size_t i) { return arr[i]; }
    int & front()              { return arr[0]; }

    // etc.

private:
    int * arr;
};

另一个用例是当您返回对传入的对象的引用时。典型的例子是像这样的可链接操作,返回引用有很多好的用途。一个是,如您所说,模拟本机解引用操作符:

struct Goo
{
    int & operator[](size_t i) { return arr[i]; }
    int & front()              { return arr[0]; }

    // etc.

private:
    int * arr;
};

另一个用例是当您返回对传入的对象的引用时。典型的例子是像这样的可链接操作,我个人喜欢在实现单例模式时返回对静态变量的引用

SomeClass& getTheSingleton()
{
    static SomeClass theInstance;
    return theInstance;
}

我不必编写任何涉及指针是否初始化的逻辑,它让我可以控制静态初始化的顺序。就我个人而言,当我想要实现单例模式时,我喜欢返回对静态变量的引用

SomeClass& getTheSingleton()
{
    static SomeClass theInstance;
    return theInstance;
}

我不必编写任何涉及某个指针是否初始化的逻辑,它让我可以控制静态初始化的顺序

使用智能指针的不同对象不会有同样的问题。智能指针总是按值存储,存储值的人拥有指针。我看不出有什么问题。我也不知道你说的返回一个真正安全的参考是什么意思。您能说明为什么运算符[]返回引用不如使用set函数安全吗?为什么只返回引用?相同的参数对于指针是有效的。除非您存储了对智能指针的引用,否则sfrabbt不存在,这是一个未知数,因为您总是按值存储智能指针,或者它们是没有价值的。v是局部的,v@sftrabbit包含的任何值也是局部的。在这种情况下,RVO、NRVO和move语义对您毫无帮助,因为您不会返回要从中移动的过期值,也不会使用可以通过RVO就地构造的临时值。复制对象是没有办法的,因为最终会有两个,而不是一个,这可能会很昂贵。使用智能指针的不同对象不会有同样的问题。智能指针总是按值存储,存储值的人拥有指针。我看不出有什么问题。我也不知道你说的返回一个真正安全的参考是什么意思。您能说明为什么运算符[]返回引用不如使用set函数安全吗?为什么只返回引用?相同的参数对于指针是有效的。除非您存储了对智能指针的引用,否则sfrabbt不存在,这是一个未知数,因为您总是按值存储智能指针,或者它们是没有价值的。v是局部的,v@sftrabbit包含的任何值也是局部的。在这种情况下,RVO、NRVO和move语义对您毫无帮助,因为您不是
t返回要移动的到期值,或使用可通过RVO就地构建的临时值。复制对象是没有办法的,因为你最终会得到两个,而不是一个,这可能会很昂贵。+1,但要小心最后一个例子,静态销毁顺序和所有的jazz。+1,但要小心最后一个例子,静态销毁顺序和所有的jazz。