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

时间:2021-07-24 17:13:33

Suppose I have a class Foo with a std::string member str. What should get_str return?

假设我有一个带有std :: string成员str的类Foo。 get_str应该返回什么?

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

or

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

What is more idiomatic in C++?

什么是C ++更惯用?

8 个解决方案

#1


15  

The short answer is: it depends :-)

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

From the performance point of view returning a reference is (usually) better: you save the creation of a new std::string object. (In this case, the creation is costly enough and the size of the object is high enough to justify make this choice at least worth considering - but this is not always the case. With a smaller or built-in type the performance difference may be negligible, or returning by value may even be cheaper).

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

From the security point of view returning a copy of the original value may be better, as constness can be cast away by malicious clients. This is especially to be taken into consideration if the method is part of a public API, i.e. you(r team) have no full control over how the returned value is (mis)used.

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

#2


7  

One of the goals of having an accessor method is to try, at least to some extent, to abstract your class implementation from its interface.

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

Returning by value is better because there are no lifetime issues with the referenced object. Should you decide not to have a std::string member but, say, a std::stringstream or to create a std::string on the fly you don't have to change the interface.

按值返回更好,因为引用的对象没有生命周期问题。如果您决定不使用std :: string成员,比如std :: stringstream或者动态创建std :: string,则不必更改接口。

Returning by const reference isn't the opposite of taking a parameter by const reference, taking a value by const reference doesn't tie your internal data representation to the external interface.

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

#3


4  

In general (unless there's a proven performance issue) I would return by value.

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

First of all there's a semantic difference, if your property changes do you want your clients to be updated of the change or get the value at the moment of calling the function?

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

There's the obvious correctness issue, if you return by reference the entity calling the function may hold on to the reference and may use it after your object was destructed (which is not so good).

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

Another problem is with multiple threaded code, if one thread reads from the const reference while you're updating the variable your in for lots of trouble.

另一个问题是多线程代码,如果一个线程从const引用中读取,而您正在更新变量,那么就会遇到很多麻烦。

In any case I think the most common use case is when the caller of the function stores the value in a variable.

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

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

If this is true (as opposed to cout << obj->get_str() where there is no variable) you always have to construct a new string for val even if you return by reference and since compilers can perform RVO the by-value version will not under-perform the by-const-ref variant.

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


In conclusion: if you know it's a performance issue and you are sure that the return value will not be stored for longer than your object will exist and you don't expect to be used from different threads, then it's OK to return by const reference.

总结:如果你知道这是一个性能问题,并且你确定返回值的存储时间不会超过你的对象存在而你不希望从不同的线程中使用,那么可以通过const引用返回。

#4


2  

Returning by value means you do not have to have an internal std::string stored somewhere in the class for which you return.

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

In a pure virtual method it is preferable not to assume that the std::string will be there and therefore to return a std::string by value.

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

In a concrete class where there is clearly a std::string member and you are just going to return a reference to it, you can, for efficiency, return it by const reference. Even if you have to change it later, you do not need to change functionality that uses the class.

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

In a multi-threaded model where the inner string might change between calls, of course, you probably need to return by value (assuming that users of the class will get a "snapshot" view of the string value at the time of the completion of the call).

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

Returning by reference is usually more efficient. I do however have a non-mutable reference-counted string class that you can return by value efficiently and I used to use that quite frequently.

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

By the way, some would recommend returning a std::string by const value. I do not think it is the best way to do it, as it prevents allowing the user to "swap" it into a local variable.

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

#5


1  

AFAIK, the rule is same as the one which is used while deciding whether to take a function parameter by value or const reference. If the sizeof the value being returned is small enough then I tend to use returning a copy else return a const reference.

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

#6


0  

I believe the second implementation (const reference) is correct as:

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

  1. the returned object is immutable and therefore upholds the rules of encapsulation.
  2. 返回的对象是不可变的,因此坚持封装规则。

  3. it's slightly more efficient as there is no copying of str.
  4. 由于没有复制str,因此效率稍高。

However the first approach will work almost as well.

然而,第一种方法几乎也可以。

#7


0  

Generally you should return PODs by value (e.g, int, short, char, long etc,) and a const reference for more complex types:

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

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

#8


-1  

It depends on what you want to do with the return value.

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

This is better if you just want to make a query and not modify str.

如果您只想进行查询而不是修改str,这样会更好。

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

Otherwise, go for this:

否则,去吧:

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

And if you want a copy/clone of str, then use this:

如果你想要str的副本/克隆,那么使用:

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

#1


15  

The short answer is: it depends :-)

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

From the performance point of view returning a reference is (usually) better: you save the creation of a new std::string object. (In this case, the creation is costly enough and the size of the object is high enough to justify make this choice at least worth considering - but this is not always the case. With a smaller or built-in type the performance difference may be negligible, or returning by value may even be cheaper).

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

From the security point of view returning a copy of the original value may be better, as constness can be cast away by malicious clients. This is especially to be taken into consideration if the method is part of a public API, i.e. you(r team) have no full control over how the returned value is (mis)used.

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

#2


7  

One of the goals of having an accessor method is to try, at least to some extent, to abstract your class implementation from its interface.

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

Returning by value is better because there are no lifetime issues with the referenced object. Should you decide not to have a std::string member but, say, a std::stringstream or to create a std::string on the fly you don't have to change the interface.

按值返回更好,因为引用的对象没有生命周期问题。如果您决定不使用std :: string成员,比如std :: stringstream或者动态创建std :: string,则不必更改接口。

Returning by const reference isn't the opposite of taking a parameter by const reference, taking a value by const reference doesn't tie your internal data representation to the external interface.

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

#3


4  

In general (unless there's a proven performance issue) I would return by value.

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

First of all there's a semantic difference, if your property changes do you want your clients to be updated of the change or get the value at the moment of calling the function?

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

There's the obvious correctness issue, if you return by reference the entity calling the function may hold on to the reference and may use it after your object was destructed (which is not so good).

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

Another problem is with multiple threaded code, if one thread reads from the const reference while you're updating the variable your in for lots of trouble.

另一个问题是多线程代码,如果一个线程从const引用中读取,而您正在更新变量,那么就会遇到很多麻烦。

In any case I think the most common use case is when the caller of the function stores the value in a variable.

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

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

If this is true (as opposed to cout << obj->get_str() where there is no variable) you always have to construct a new string for val even if you return by reference and since compilers can perform RVO the by-value version will not under-perform the by-const-ref variant.

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


In conclusion: if you know it's a performance issue and you are sure that the return value will not be stored for longer than your object will exist and you don't expect to be used from different threads, then it's OK to return by const reference.

总结:如果你知道这是一个性能问题,并且你确定返回值的存储时间不会超过你的对象存在而你不希望从不同的线程中使用,那么可以通过const引用返回。

#4


2  

Returning by value means you do not have to have an internal std::string stored somewhere in the class for which you return.

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

In a pure virtual method it is preferable not to assume that the std::string will be there and therefore to return a std::string by value.

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

In a concrete class where there is clearly a std::string member and you are just going to return a reference to it, you can, for efficiency, return it by const reference. Even if you have to change it later, you do not need to change functionality that uses the class.

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

In a multi-threaded model where the inner string might change between calls, of course, you probably need to return by value (assuming that users of the class will get a "snapshot" view of the string value at the time of the completion of the call).

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

Returning by reference is usually more efficient. I do however have a non-mutable reference-counted string class that you can return by value efficiently and I used to use that quite frequently.

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

By the way, some would recommend returning a std::string by const value. I do not think it is the best way to do it, as it prevents allowing the user to "swap" it into a local variable.

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

#5


1  

AFAIK, the rule is same as the one which is used while deciding whether to take a function parameter by value or const reference. If the sizeof the value being returned is small enough then I tend to use returning a copy else return a const reference.

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

#6


0  

I believe the second implementation (const reference) is correct as:

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

  1. the returned object is immutable and therefore upholds the rules of encapsulation.
  2. 返回的对象是不可变的,因此坚持封装规则。

  3. it's slightly more efficient as there is no copying of str.
  4. 由于没有复制str,因此效率稍高。

However the first approach will work almost as well.

然而,第一种方法几乎也可以。

#7


0  

Generally you should return PODs by value (e.g, int, short, char, long etc,) and a const reference for more complex types:

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

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

#8


-1  

It depends on what you want to do with the return value.

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

This is better if you just want to make a query and not modify str.

如果您只想进行查询而不是修改str,这样会更好。

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

Otherwise, go for this:

否则,去吧:

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

And if you want a copy/clone of str, then use this:

如果你想要str的副本/克隆,那么使用:

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