20

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

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

or

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

What is more idiomatic in C++?

fredoverflow
  • 256,549
  • 94
  • 388
  • 662
  • I asked a very similar question: http://stackoverflow.com/questions/134731/returning-a-const-reference-to-an-object-instead-of-a-copy – Rob Jan 06 '11 at 12:04
  • Also, you might be interested in this [stack-exchange proposal](http://area51.stackexchange.com/proposals/11464/code-review?referrer=aWNm_PdciyFqjFW8CUacGw2 "code review"). It's almost ready to begin beta, just needs a few more. :) – greatwolf Jan 18 '11 at 08:08

8 Answers8

18

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).

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.

Péter Török
  • 114,404
  • 31
  • 268
  • 329
  • 2
    +1, this is a pretty good point sir. Indeed, API code should never expose private members, even indirectly. – Alexandre C. Jan 06 '11 at 10:24
  • How long is a piece of `std::string`? On many implementations copying a short `std::string` is cheap (depending on what you are measuring it against). – CB Bailey Jan 06 '11 at 10:26
  • 1
    @Charles, I seem to remember that on Visual C++ platform the size of an empty `string` was 20 bytes, but of course it is implementation dependent. I did not mean that the performance benefit is always clear for `std::string&`, but my wording was unclear - now I clarified it. – Péter Török Jan 06 '11 at 10:37
  • 2
    You basically have to trust users of your API not to work around the `const` modifiers. They are shooting themselves in the foot, and if the code doesn't work it is their own fault. That said, I don't find *hiding data* to be a good reason to not return a `const`. – edA-qa mort-ora-y Jan 06 '11 at 11:14
  • 1
    @edA-qa mort-ora-y, sometimes trusting your clients is an option, sometimes it is not. It is good to be aware of one's (lack of) choices. – Péter Török Jan 06 '11 at 11:49
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.

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.

CB Bailey
  • 755,051
  • 104
  • 632
  • 656
  • Nothing prevents you from having additional `std::string` members strictly for the purpose of returning from functions. Just copy to it in the function and return. – edA-qa mort-ora-y Jan 06 '11 at 11:16
  • @edA-qa mort-ora-y: That is true but it implies a maintenance (code complexity) and run time size overhead if that's the only reason you have such a member. – CB Bailey Jan 06 '11 at 11:18
  • I agree. I just wanted to point out that using a `const &` doesn't prevent backwards compatibility (you don't need to change the interface even if the internals change). – edA-qa mort-ora-y Jan 06 '11 at 11:22
5

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.

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.


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.

Motti
  • 110,860
  • 49
  • 189
  • 262
  • Though I disagree to return by value by default, your point about multi-threading is significant. If the object is thread-safe it should not be returning references to data that can change in another thread. *Excluding some external locking mechanism of course* – edA-qa mort-ora-y Jan 06 '11 at 11:18
2

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

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.

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.

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.

CashCow
  • 30,981
  • 5
  • 61
  • 92
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.

Naveen
  • 74,600
  • 47
  • 176
  • 233
  • 2
    sizeof(std::string) is small enough, but copying efficiency depends on the size of string – Andriy Tylychko Jan 06 '11 at 10:23
  • 1
    The same issues don't affect taking parameters as returning values. returning a reference requires to called entity to actually maintain an object after the function has returned. Taking a `const` reference (usually) only requires the caller to maintain an object up to a well defined point: the return of the function. – CB Bailey Jan 06 '11 at 10:24
1

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

int getData() const;
short getMoreData() const;
const std::string& getName() const;
const ComplexObject& getComplexData() const;
Moo-Juice
  • 38,257
  • 10
  • 78
  • 128
0

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

  1. the returned object is immutable and therefore upholds the rules of encapsulation.
  2. it's slightly more efficient as there is no copying of str.

However the first approach will work almost as well.

trojanfoe
  • 120,358
  • 21
  • 212
  • 242
-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.

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:

std::string Foo::get_str() const
{
    return str;
}
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • that looks as the worst of all worlds, isn't it? giving a client direct access to objects private data. I'd definitely vote for return by value in the second case – davka Jan 06 '11 at 10:22
  • The second case is a different scenario to returning by const-reference or value which are both equivalent much of the time. – CashCow Jan 06 '11 at 10:28
  • std::string& Foo::get_str() - most often do not do this. You want to modify your members in your class, not let to modify anyone else. – Suma Jan 06 '11 at 10:55