' const string& getName()const {}' vs' string getName()const {}'?

时间:2015-02-11 02:02:28

标签: c++

现在,这是高度概念性的。我不知道我是否理解这一点,所以请帮助我理解其中的差异。

我们假设namestd::string访问者函数访问的私有getName()数据成员:

const string& getName() const {
       return name;  
}

现在,这将向name返回一个引用,它只是别名的另一个词。因此,返回别名,即返回name数据成员。是允许还是会破坏数据隐藏的全部目的?

换句话说,上述方法究竟与传统方法有何不同:

string getName() const {
     return name;
}

???

最后,真的值得实施前者而不是后者吗?

3 个答案:

答案 0 :(得分:3)

首先,如果底层值可能发生变化,那么引用确实会有问题,特别是在多线程执行的上下文中。因此,几乎是一个基本的假设,即数据成员的值在对象的生命周期内不会改变。它实际上是一个常数。

现在,引用的一个主要问题是它暴露了一个实现细节,因此很难改变实现。

一个更具学术性的问题是它可以破坏代码,如果之前有一个按值返回,或者只是因为它是不寻常的。 E.g。

const string s& = foo().name();

foo()按值返回一个对象,name()通过引用返回一个字符串,这会给你一个悬空引用,而不是天真预期的延长生命周期。我称之为学术,因为我无法想象有人写这个。不过,墨菲定律和所有这些。

它可能不会(显着)比值返回更有效,正是因为它不太可能仅用于初始化引用。

所以:

  • 可能效率不高,

  • 阻止轻松更改实施,

  • 也存在学术问题,产生了悬空参考。

总而言之,就是不要。

这是过早的优化和复杂化。

答案 1 :(得分:1)

第一个允许调用者 - 可以直接访问您的内部名称变量。当然它是常量,所以它们只能调用const方法。但您是否仍希望外部呼叫者对您隐藏的内部数据进行操作?更糟糕的是,如果一些bozo决定const_cast字符串的内部数据缓冲区并破解它呢?

第二个返回内部名称变量的副本。任何来电者都可以使用。

我通常会偏离第一种类型,除了琐碎的低级别类型。但是,无论如何,琐碎的低级类型都没有太多的复制开销。所以这意味着我从不写那样的东西。

答案 2 :(得分:-1)

const引用返回更好,因为它不会复制字符串。我之所以这么说是因为界面更灵活 - 你可以随时将const引用复制到另一个字符串中,或​​者你可以将它作为参考 - 直到调用者。返回一个byvalue成员,你总是坚持复制。如果name很大或经常使用,那么它会影响性能,我认为性能是你首先使用C ++的原因之一。

现在,其他答案提出了一些关于返回const引用的负面观点,我认为这种观点无效。

您可以抛弃const的问题是有效的,但抛弃const只是C ++开发人员工具箱中的工具之一。为什么把它带走?如果有人真的想弄乱你的对象,他们总是可以通过直接解决内存来用c ++这样做,所以设计你的代码来保存你自己的调用者是没有意义的。将const转移出来显示出这样做的意图,在我看来是完全可以的。这意味着调用者有一些非常具体的理由这样做并且知道被抛弃的const是非const对象,因此是安全的。

另一个答案的学术范例很愚蠢:

const string s& = foo().name();

同样,设计代码以尝试从其自身保存调用者会限制您使用C ++的强大功能。如果真的想要做到这一点,那么正确的方法就是

string s = foo().name();

所以这一点也没有实际意义。

唯一有效的一点是它稍微暴露了实现。然而,在我看来,效率提升超过了这个问题。

你真正应该问自己的是 - 使用name()的常见情况是什么?

通过回答这个问题,您将回答应该使用的风格。

对我而言,它被称为name这一事实意味着它主要用于打印/记录和比较。因此,const引用在这里是明显的赢家。

另外,请查看那里的风格指南。他们中的大多数将通过const引用传递并通过const引用返回成员。如上所述,有很好的理由这样做。