What\'s better as default, to return a copy (1) or a reference (2) from a getter function?
class foo {
public:
std::string str () { // (1)
The only problem I have with returning a const-reference, which is something I would typically do for non basic types, is that there is nothing to stop the caller removing the "const"ness and then modifying the value.
Personally, I'd suggest that such code is a bug. If they know you're returning a reference and continue to cast away the const then it's on their head.
I'm returning a reference, because a string seems not "cheap to copy" to me. It's a complex data type with dynamic memory management and all that.
The "if you want the caller to get a copy, you should return by value" argument is moot, because it doesn't preclude copies at all. The caller can still do the following and get a copy anyway
string s = obj.str();
You need to explicitly create a reference on the caller side to be able to refer to the data member directly afterwards - but why would you do that? There definitely are enough user defined types that are cheap to copy
If there is no special reason to use a value type as return value, I always return a const reference. If I need (or expect to need) a (writable) copy, I add a copy ctor and an assignment operator to the returned class if not already available. For the usage think of:
const MyClass & ref = container.GetAt( 1234 ); // need only reference
MyClass copy = container.GetAt( 1234 ); // get writable copy
Actually this is quite straight forward, isn't it?
Well it really depends on what you expect the behaviour to be, by default.
Do you expect the caller to see changes made to str_ unbeknownst(what a word!) to them? Then you need to pass back a reference. Might be good if you can have a refcounted data member and return that.
If you expect the caller to get a copy, do 1).
The compiler will not be able to perform (N)RVO in this case. The (named) return value optimization is an optimization where the compiler creates the function auto variables in the place of the return value to avoid having to copy:
std::string f()
{
std::string result;
//...
return result;
}
When the compiler sees the code above (and assuming that if any other return is present it will also return the result
variable) it knows that the variable result
has as only possible fate being copied over the returned temporary and then destroyed. The compiler can then remove the result
variable altogether and use the return temporary as the only variable. I insist: the compiler does not remove the return temporary, it removes the local function variable. The return temporary is required to fulfill the compilers call convention.
When you are returning a member of your class, the member must exist, and the call convention requires the returned object to be in a particular location (stack address usually). The compiler cannot create the method attribute over the returned object location, nor can it elide making the copy.
if its a small basic type - primatives like int and long and their wrappers and other basic things like 'Point' - return a copy
if its a string, or any other complex type - return a reference.