fredoverflow
fredoverflow

Reputation: 263310

Should accessors return values or constant references?

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++?

Upvotes: 20

Views: 9887

Answers (8)

Motti
Motti

Reputation: 114805

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 you're 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.

Upvotes: 6

CB Bailey
CB Bailey

Reputation: 792837

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.

Upvotes: 7

P&#233;ter T&#246;r&#246;k
P&#233;ter T&#246;r&#246;k

Reputation: 116306

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.

Upvotes: 18

CashCow
CashCow

Reputation: 31445

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.

Upvotes: 2

Moo-Juice
Moo-Juice

Reputation: 38820

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;

Upvotes: 1

Sarfaraz Nawaz
Sarfaraz Nawaz

Reputation: 361692

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;
}

Upvotes: -1

trojanfoe
trojanfoe

Reputation: 122429

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.

Upvotes: 0

Naveen
Naveen

Reputation: 73493

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.

Upvotes: 1

Related Questions