访问者应该返回值还是常量引用?

时间:2011-01-06 10:14:45

标签: c++ reference return-value accessor

假设我有一个Foo成员std::string的班级strget_str应该返回什么?

std::string Foo::get_str() const
{
    return str;
}

const std::string& Foo::get_str() const
{
    return str;
}

C ++中有什么更惯用的东西?

8 个答案:

答案 0 :(得分:16)

简短的回答是:它取决于: - )

从性能的角度来看,返回引用(通常)更好:保存新std::string对象的创建。 (在这种情况下,创建的成本足够高,并且对象的大小足够高以使对齐使这个选择至少值得考虑 - 但情况并非总是如此。在类型中,性能差异可以忽略不计,或者按值返回甚至可能更便宜)。

从安全的角度来看,返回原始值的副本可能会更好,因为constness可能被恶意客户端抛弃。如果该方法是公共API的一部分,则特别需要考虑这一点,即您(团队)无法完全控制返回值的使用方式(错误)。

答案 1 :(得分:7)

使用访问器方法的目标之一是至少在某种程度上尝试从其接口中抽象出类实现。

按值返回更好,因为引用的对象没有生命周期问题。如果您决定不拥有std::string成员,但比如说std::stringstream或者即时创建std::string,则无需更改界面。

通过const引用返回与通过const引用获取参数的方式不同,将值const引用不会将内部数据表示与外部接口绑定。

答案 2 :(得分:4)

一般情况下(除非有经证实的性能问题)我会按价值返回。

首先,存在语义差异,如果您的属性发生更改,您是否希望客户端更新更改或在调用函数时获取值?

有明显的正确性问题,如果通过引用返回,调用该函数的实体可以保留引用,并且可以在对象被破坏后使用它(这不太好)。

另一个问题是多线程代码,如果一个线程在你更新变量时从const引用中读取,那就很麻烦了。

在任何情况下,我认为最常见的用例是函数的调用者将值存储在变量中。

string val = obj->get_str();
// use val now

如果这是真的(与没有变量的cout << obj->get_str()相反),即使您通过引用返回并且编​​译器也可以执行{{3},您总是必须为val构造一个新字符串。 by-value版本不会低于执行by-const-ref变体。


总结:如果您知道性能问题 ,那么肯定,返回值的存储时间不会超过您的对象将存在你不希望从不同的线程使用,那么可以通过const引用返回。

答案 3 :(得分:2)

按值返回意味着您不必将一个内部std :: string存储在您返回的类中的某个位置。

在纯虚方法中,最好不要假设std :: string存在,因此按值返回std :: string。

在一个具有std :: string成员的具体类中,你只是要返回对它的引用,为了提高效率,你可以通过const引用返回它。即使您以后必须更改它,也不需要更改使用该类的功能。

在一个多线程模型中,内部字符串可能在调用之间发生变化,当然,您可能需要按值返回(假设该类的用户将获得该字符串值的“快照”视图)完成电话会议。)

通过引用返回通常更有效。但是,我确实有一个不可变的引用计数字符串类,你可以有效地返回值,而我过去常常使用它。

顺便说一下,有人会建议用const值返回一个std :: string。我不认为这是最好的方法,因为它阻止允许用户将其“交换”到本地变量。

答案 4 :(得分:1)

AFAIK,规则与决定是否通过值或const引用获取函数参数时使用的规则相同。如果返回的sizeof值足够小,那么我倾向于使用返回一个副本,否则返回一个const引用。

答案 5 :(得分:0)

我相信第二个实现(const引用)是正确的:

  1. 返回的对象是不可变的,因此坚持封装规则。
  2. 由于没有str的复制,因此效率稍高。
  3. 然而,第一种方法几乎也可以。

答案 6 :(得分:0)

通常你应该按值返回POD(例如,int,short,char,long等),以及更复杂类型的const引用:

int getData() const;
short getMoreData() const;
const std::string& getName() const;
const ComplexObject& getComplexData() const;

答案 7 :(得分:-1)

这取决于你想要对返回值做什么。

如果您只是想进行查询而不是修改str,那就更好了。

const std::string& Foo::get_str() const
{
    return str;
}

否则,请执行此操作:

std::string& Foo::get_str()
{
    return str;
}

如果您想要str副本/克隆,请使用此功能:

std::string Foo::get_str() const
{
    return str;
}