16

我对将 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 有什么好处吗?

4

4 回答 4

15

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

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

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

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

于 2012-11-22T07:42:36.773 回答
13

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

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

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

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

如果更改为按值返回而不是 const 引用,则此代码当然会产生一个不再编译的悬空指针。 (感谢史蒂夫杰索普纠正我)Get()

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

class sample
{
  std::string mString;

public:
  void Set(const std::string &s)
  {
    mString = s;
  }
  std::string Get() const
  {
    return mString;
  }
};
于 2012-11-22T07:44:01.917 回答
7

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

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

如果您确实需要返回字符串的副本,则可以通过使用“最重要的 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
于 2012-11-22T10:28:13.647 回答
0

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

于 2012-11-22T07:29:58.970 回答