在getter函数中返回const引用或副本?

cai*_*rol 41 c++ const return-value

默认情况下,从getter函数返回副本(1)或引用(2)会更好吗?

class foo {
public:
    std::string str () { // (1)
        return str_;
    }

    const std::string& str () { // (2)
        return str_;
    }

private:
    std::string str_;
};
Run Code Online (Sandbox Code Playgroud)

我知道2)可能更快,但不必因(N)RVO.1)关于悬挂引用更安全,但对象可能会过时或永远不会存储引用.

当你写一个课程时,你的默认值是什么,而且还不知道(但)性能和生命周期问题是否重要?

附加问题:当成员不是普通字符串而是向量时,游戏会改变吗?

小智 22

嗯,这实际上取决于你对行为的期望,默认情况下.

你是否希望调用者能够看到对str_ unbeknownst(一句话!)所做的更改?然后你需要传回一个参考.如果你有一个refcounted数据成员并返回该成员,可能会很好.

如果您希望调用者获得副本,请执行1).


Nav*_*een 18

我的经验法则是返回简单基本数据类型的副本,例如int,string等.对于更复杂的结构,复制可能更昂贵(就像你提到的向量)我更喜欢返回const-reference.


Dav*_*eas 10

在这种情况下,编译器将无法执行(N)RVO.(命名)返回值优化是一种优化,其中编译器在返回值的位置创建函数自动变量,以避免必须复制:

std::string f()
{
   std::string result;
   //...
   return result;
}
Run Code Online (Sandbox Code Playgroud)

当编译器看到上面的代码时(并假设如果存在任何其他返回,它也将返回result变量)它知道变量result只有可能的命运被复制到返回的临时,然后被销毁.然后编译器可以result完全删除变量并使用return temporary作为唯一变量.我坚持:编译器不会删除返回临时,它会删除本地函数变量.返回临时值是完成编译器调用约定所必需的.

当您返回类的成员时,该成员必须存在,并且调用约定要求返回的对象位于特定位置(通常是堆栈地址).编译器无法在返回的对象位置上创建方法属性,也无法进行复制.


Joh*_*itb 7

我正在返回一个引用,因为字符串看起来并不"复制"给我.它是一种复杂的数据类型,具有动态内存管理等等.

"如果你想让调用者获得一个副本,你应该按值返回"这个论点没有实际意义,因为它根本不排除副本.无论如何,呼叫者仍然可以执行以下操作并获得副本

string s = obj.str();
Run Code Online (Sandbox Code Playgroud)

您需要在调用者端明确创建一个引用,以便之后能够直接引用数据成员 - 但为什么要这样做?肯定有足够的用户定义类型,便宜复制

  • 智能指针
  • 迭代器
  • 所有非类型.