【问题标题】:Return std::string as const reference返回 std::string 作为 const 引用
【发布时间】:2012-11-10 13:21:08
【问题描述】:

我对返回 std::string 作为 const 引用有疑问。

class sample
{
public:
  std::string mString;
  void Set(const std::string& s)
  {
    mString = s;
  }
  std::string Get()
  {
    return mString;
  }
 };

在 Set 函数中,我将 std::string 作为 const 引用传递,因为它的值在函数内部没有变化。

而在 Get 函数中,其实我在这里很困惑。将 std::string 作为值返回更有意义。但我不确定通过将字符串作为 const 引用传递是否有任何优势。我认为通过将字符串作为参考来提高执行速度,但我不确定。但是将其返回为 'const 有什么好处吗?

【问题讨论】:

    标签: c++ string reference constants stdstring


    【解决方案1】:

    通过引用或 const 引用返回没有速度差异 - 两者都非常快,因为它们只是返回对原始对象的引用,不涉及复制。

    (非常量)引用返回的对象可以通过该引用进行修改。在您的具体示例中,mString 是公开的,因此无论如何都可以(直接)修改它。但是,getter 和 setter 的常用方法(以及引入它们的主要原因)是封装 - 您只允许通过 getter/setter 访问您的数据成员,以便您可以检测正在设置的无效值、响应值更改和只是通常将类的实现细节隐藏在其中。所以 getter 通常通过 const 引用或值返回。

    但是,如果您通过 const 引用返回,它会将您绑定到始终在您的类中保留 std::string 的实例以备份引用。也就是说,即使您稍后想要重新设计您的类,以便它在 getter 中动态计算字符串,而不是在内部存储它,您也不能。您必须同时更改您的公共接口,这可能会破坏使用该类的代码。例如,只要您通过 const-reference 返回,这是完全有效的代码:

    const std::string *result = &aSample.Get();
    

    如果 Get() 更改为按值返回而不是 const 引用,此代码当然会产生一个悬空指针 不再编译(感谢 Steve Jessop 纠正我)

    总而言之,我将采取的方法是将mString 设为私有。 Get() 可以通过值或常量引用返回,这取决于您对始终存储字符串的确定程度。然后该类将如下所示:

    class sample
    {
      std::string mString;
    
    public:
      void Set(const std::string &s)
      {
        mString = s;
      }
      std::string Get() const
      {
        return mString;
      }
    };
    

    【讨论】:

    • “如果将 Get() 更改为按值返回而不是 const 引用,则此代码当然会产生一个悬空指针。” -- 不,它不会,它将停止编译(“不能获取临时地址”)。这比使用 UB 编译要好。实际上,由于扩展,它可以编译,但我不认为这是一个常见的扩展,标准仍然需要诊断,因此至少应该警告用户。
    • +1 用于备注如果您通过 const 引用返回,它会绑定您始终在您的类中保留 std::string 的实例以备份引用
    【解决方案2】:

    这里最常见的做法是将值作为常量引用返回,然后您可以根据需要使用引用或复制该值:

    const std::string& Get() const
    {
        return mString;
    }
    
    sample mySample;
    const std::string &refString = mySample.Get(); // Const-reference to your mString
    const std::string copyString = mySample.Get(); // Copy of your mString
    

    如果您确实需要返回字符串的副本,那么您可以通过使用“The Most Important Const”来避免复制字符串返回值:

    sample mySample;
    const std::string &myString = mySample.Get();
    // myString is now valid until it falls out of scope, even though it points to a "temporary" variable
    

    【讨论】:

      【解决方案3】:

      决定如何从某种容器中返回一个重要对象的问题实际上并不重要:

      • 如果返回值的类对对象施加任何类型的约束,则不能返回非const 引用,因为它会失去强制执行其不变量的可能性。显然,通过非const 引用返回对象只有在调用成员函数的对象也是非const 时才可行。
      • 向对象公开const 引用可以避免不变量的问题,但仍然意味着相应类型的对象实际上作为实现细节保留在内部。
      • 按值返回对象可能会导致复制对象的大量成本。

      如果你的类更进一步是一个可行的monitor,你肯定希望按值返回对象,否则对象可能在调用者有机会复制它之前发生变异。

      基本上,没有一个选择是理想的。如有疑问,我会按值返回,除非知道复制对象的成本很高,在这种情况下我可能返回const&

      【讨论】:

      • 是的。我知道这是一个老问题,但尤其是在接口的情况下,不想对实现施加限制,按值返回通常更好。
      【解决方案4】:

      将其作为参考返回。如果需要副本,当然可以从该参考文献中制作。

      【讨论】:

      • 将它返回为 'const' 怎么样??
      • 如果你希望你的字符串只被Set方法修改,定义Getconst std::string &Get () const { return mString; }
      猜你喜欢
      • 1970-01-01
      • 2015-08-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多