1

Now, this is highly conceptual. I don't know if I understand this correctly, so please help me understand the difference.

Let's assume that name is a private std::string data member that is accessed by the getName() accessor function:

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

Now then, this returns a reference, which is just another word for alias, to name. So, an alias is being returned, i.e. the name data member is being returned. Is this allowed or will it defeat the whole purpose of data hiding?

In other words, how exactly is the above method different to the conventional:

string getName() const {
     return name;
}

???

And finally, is it really worth implementing the former instead of the latter?

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
abcde
  • 505
  • 1
  • 5
  • 8

3 Answers3

3

First of all, the reference would be problematic indeed if the underlying value could change, particularly in the context of multi-threaded execution. So it's almost a basic assumption that the value of the data member doesn't change during the lifetime of the object. That it's effectively a constant.

Now, a main problem with the reference is that it exposes an implementation detail so that it gets difficult to change the implementation.

A more academic problem is that it can break code, if there earlier was a by-value return, or just because it's unusual. E.g.

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

With foo() returning an object by value, and name() returning a string by reference, this gives you a dangling reference instead of the naïvely expected prolonged lifetime. I call it academic because I can't imagine anyone writing that. Still, Murphy's law and all that.

It will probably not be (significantly) more efficient than a value return, precisely because it's unlikely that it's used just to initialize a reference.

So:

  • probably not significantly more efficient,

  • prevents changing implementation easily,

  • also has an academic problem, yielding dangling references.

In sum, just don't.

This is premature optimization and complication.

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • *It will probably not be more efficient than a value return, precisely because it's unlikely that it's used just to initialize a reference* - I strongly disagree with this. The fact that it is called `name` implies that it will most likely be used for comparison, printing/logging, as a key in a map, etc. Most of those uses **will** be more efficient. Now, your academic example is just pushing it ... all you have to do is `string s =` and your problem disappears and it becomes as (in)efficient as the byvalue solution. – Rado Feb 11 '15 at 15:44
  • @Rado: Let's amend my statement to “significantly more efficient”. Using a dictionary of 58112 lowercase words, looking up the word “quickly” 1 million times in a `std::map`, with MinGW g++ 4.9.1 and `-O2` I got (as typical example) 0.117085 seconds elapsed for value-returns, and 0.109069 seconds elapsed for ref-returns. With Visual C++ 13.0 and `/O2` I got 0.218411 seconds elapsed for value-returns 0.200394 seconds elapsed for ref-returns. IMHO that's a very marginal optimization, absolutely not worth it. Code at (http://codepad.org/n7rkUc9T). – Cheers and hth. - Alf Feb 11 '15 at 18:53
1

The first allows callers some-what direct access to your internal name variable. Granted it's constant, so they can only call const methods on it. But still do you want external callers operating on your hidden, internal data? Even worse, what if some bozo decides to const_cast the internal data buffer of the string and hack on it?

The second returns a copy of your internal name variable. Perfectly safe for any callers to use.

I usually steer away from the first type, except for trivial, low level types. But then trivial low level types don't have much overhead for copying anyways. So that means I never write stuff like that.

C.J.
  • 15,637
  • 9
  • 61
  • 77
-1

The const reference return is better since it does not make a copy of the string. The reason I say this is because the interface is more flexible this way - you can always copy the const reference into another string if needed or you can use it as a reference - up to the caller. Returning a member byvalue and you are always stuck with making a copy. If name is big or used often, then it will impact performance and I assume performance is one of the reasons you use C++ in the first place.

Now, the other answers raise some negative points about returning a const reference, which I do not think are valid.

The concern that you can cast away the const, is valid, but casting away const is just one of the tools in the C++ developer's toolbox. Why take it away? If someone really wants to mess with your object, they can always do so in c++ by addressing memory directly so designing your code to save your callers from themselves is pointless. Casting the const away shows intent to do so and in my opinion is perfectly OK. It means that the caller has some very specific reasons to do so and knows that the const being cast away is for a non-const object and therefore - safe.

The academic example in the other answer is just silly:

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

Again, designing your code to attempt to save the caller from themselves is limiting you from the power of C++. If one would really want to do the above, the proper way would be

string s = foo().name();

So that point is moot too.

The only valid point is that it exposes the implementation somewhat. The efficiency gains, however, outweigh this concern in my opinion.

What you really should ask yourself is this - what is the usual case of using name()?

By answering this question, you will answer which flavour you should use.

To me, the fact that it is called name implies that it will mostly be used for printing/logging and comparison. Therefore, the const reference is the clear winner here.

Also, look at the style guides out there. Most of them will have you pass by const reference and return members by const reference. There are very good reasons to do so as outlined above.

Rado
  • 8,634
  • 7
  • 31
  • 44
  • "better" is a matter of opinion, each version has its pros and cons. There are other considerations besides just whether a copy is made. It may also depend on the most common use case for the object. – M.M Feb 11 '15 at 02:34
  • @MattMcNabb. True, I edited my answer with a better explanation ... no pun intended ;) – Rado Feb 11 '15 at 16:27