What to return -- object, reference or const reference

A

Arv

After writing code in Java for sometime, one thing that I am not
comfortable at all with C++ is the return type of an object.

In java, i do not remember ever seeing a method return a final
reference -- though a const is not equivalent to final, it is
confusing when i see some methods returning a const reference.

I initially assumed returning an object is same as returning a
reference, because when i call the method as

Myclass O1;

O1 = func();

Does it matter if func() returns a reference, const reference or a
Object, anyways the assignment operator is going to get called.

But I am a bit confused when I call AnotherFunc(func())... so is it
possible that if I dont pass a const reference, and the AnotherFunc
accepts a reference, it can potentially change the object I pass.!

Especially this is more confusing in a getter method, should a getter
return a const reference always, because I do not want ppl to modify
the reference they get by calling a getter.

Sorry if this is a bit basic, but I have not been able to understand
this very clearly...

Thanks
Arv
 
T

Tom

Does it matter if func() returns a reference, const reference or a
Object, anyways the assignment operator is going to get called.
For the assignment: I don't think so, unless you overload the assigned
operation. In that case, anything is possible.

But returning a reference allows modification of the returned object,
like:
func().MyModifyFunction();

That's why overloaded [] operator usually return a reference and not a
copy of the object.

Thomas
 
E

EventHelix.com

After writing code in Java for sometime, one thing that I am not
comfortable at all with C++ is the return type of an object.

In java, i do not remember ever seeing a method return a final
reference -- though a const is not equivalent to final, it is
confusing when i see some methods returning a const reference.

I initially assumed returning an object is same as returning a
reference, because when i call the method as

Myclass O1;

O1 = func();

Does it matter if func() returns a reference, const reference or a
Object, anyways the assignment operator is going to get called.

But I am a bit confused when I call AnotherFunc(func())... so is it
possible that if I dont pass a const reference, and the AnotherFunc
accepts a reference, it can potentially change the object I pass.!

Especially this is more confusing in a getter method, should a getter
return a const reference always, because I do not want ppl to modify
the reference they get by calling a getter.

Sorry if this is a bit basic, but I have not been able to understand
this very clearly...

Thanks
Arv

In C++ returning an object is suitable only when the object contains
only a few data members. Returning an object results in a copy of
entire object thus it can have really impact performance if objects
with a large list of data members is returned.

Note that in an object return, the copy constructor gets called (if
defined). If the copy constructor is not defined, an exact copy of the
object is returned.

An object copy can result in hard to debug memory allocation issues.
Consider the case where the object being copied contained pointers to
dynamically allocated memory. Only the pointers would be copied. Thus
both objects would be pointing to the same allocated memory.
 
J

James Kanze

After writing code in Java for sometime, one thing that I am not
comfortable at all with C++ is the return type of an object.
In java, i do not remember ever seeing a method return a final
reference -- though a const is not equivalent to final, it is
confusing when i see some methods returning a const reference.

C++ isn't Java, and you can't always make direct comparisons.
In this case, C++ has full support for value semantics, and so
allows considerably safer idioms.

Generally speaking, returning a value should be the default
action. You only return a reference when you explicitly want to
support access to internal data. In particular: you never, ever
return a reference (const or not) to a local variable or a
temporary (the results of an expression).

Typically, when you return a reference, it's because you're
allowing access to internal data: the operator[] of container
classes would be an obvious example, but one can imagine others.

Because of this, it's very, very rare to return a const
reference (although there, too, there are exceptions).
Basically, the goal behind the const reference is that the
client code can save it, and although it cannot modify the data,
it will see any modifications from other sources through the
saved reference.
I initially assumed returning an object is same as returning a
reference, because when i call the method as
Myclass O1;
O1 = func();
Does it matter if func() returns a reference, const reference
or a Object, anyways the assignment operator is going to get
called.

In this case, it probably doesn't matter. Unless, of course,
the returned value is a local variable or a temporary, in which
case, returning the reference means that the code won't work.
But I am a bit confused when I call AnotherFunc(func())... so
is it possible that if I dont pass a const reference, and the
AnotherFunc accepts a reference, it can potentially change the
object I pass.!

If you're returning a non-const reference, this is the behavior
you're targetting.
Especially this is more confusing in a getter method, should a
getter return a const reference always, because I do not want
ppl to modify the reference they get by calling a getter.

Well, mostly, you should not have that many "getter"
functions:). However... typically, a getter should return a
value. Unless, of course, what you are getting is something you
want to share.
 
J

James Kanze

In C++ returning an object is suitable only when the object
contains only a few data members. Returning an object results
in a copy of entire object thus it can have really impact
performance if objects with a large list of data members is
returned.

That's bullshit. Return by reference results in different
semantics than return by value, and you can't simply replace one
with the other. The default return type in C++ is by value
(just as the default behavior everywhere is by value). If you
have a performance problem, and the profiler shows it to be due
to excess copies, then most of the time, the solution is to use
an out parameter, rather than return by reference.
Note that in an object return, the copy constructor gets
called (if defined). If the copy constructor is not defined,
an exact copy of the object is returned.

If no accessible copy constructor is defined, you can't copy,
period. If no user-defined copy constructor is declared, the
copy is member by member, not "exact" (whatever that means---I
would assume bitwise).
An object copy can result in hard to debug memory allocation
issues. Consider the case where the object being copied
contained pointers to dynamically allocated memory. Only the
pointers would be copied. Thus both objects would be pointing
to the same allocated memory.

Not providing a copy constructor when one is needed will cause a
number of problems. Regardless of whether you return by value
or return by reference. One of the very first things one learns
in C++ is to either ensure that the copy constructor works
correctly, or that copy is inhibited.
 
D

Daniel T.

After writing code in Java for sometime, one thing that I am not
comfortable at all with C++ is the return type of an object.

In java, i do not remember ever seeing a method return a final
reference -- though a const is not equivalent to final, it is
confusing when i see some methods returning a const reference.

I initially assumed returning an object is same as returning a
reference, because when i call the method as

Myclass O1;

O1 = func();

Does it matter if func() returns a reference, const reference or a
Object, anyways the assignment operator is going to get called.

But I am a bit confused when I call AnotherFunc(func())... so is it
possible that if I dont pass a const reference, and the AnotherFunc
accepts a reference, it can potentially change the object I pass.!

Especially this is more confusing in a getter method, should a getter
return a const reference always, because I do not want ppl to modify
the reference they get by calling a getter.

Sorry if this is a bit basic, but I have not been able to understand
this very clearly...

The below rules cover most situations for both parameters and return
values.

Returning by const reference is an optimization over returning by
value that you can use when you know that the object returned will
outlive the function returning it, the caller will not likely be
making a copy of its own, but be sure to let the caller know (through
documentation) how long that reference will be good for.

Returning by non-const reference is only for special situations where
the object being returned is either something that the caller has
access to anyway (for example returning a reference parameter that was
passed in, or a global,) or something that the function is
specifically designed to allow access to (for example containers, and
lazy initializers.)

Function parameters should be passed in by non-const reference only
when the function is specifically designed to modify the object passed
in (for example if the parameter is being used as output, or input and
output.) Otherwise the parameter should be by value if its size is
known to be equal to or less than sizeof(int) and the object
constructor (if it has one) is known not to allocate memory.
Otherwise, the parameter should be a const reference.

You may notice that I didn't mention pointers in the above, they
generally follow the same rules as references when you are talking
about the object the pointer points to, they follow the same rules as
objects when you are talking about the pointer object *itself*.

In summary:

T func(); // default
const T& func(); // only when you know that the value returned will
outlive func
// and its use by the caller
T& func(); // only if the caller has access to the object anyway, or
you specifically
// want to grant access to it

void func( const T& t ); // default
void func( T t ); // if the memory required by the object is known to
be small
void func( T& t ); // if 't' is being used as an output parameter
 
R

Richard Herring

In message
<[email protected]>,

[...]
In C++ returning an object is suitable only when the object contains
only a few data members. Returning an object results in a copy of
entire object thus it can have really impact performance if objects
with a large list of data members is returned.

You're recommending premature optimisation, which is never a good idea.
If _measurement_ indicates that this copy has an impact on performance,
_then_ consider an alternative.
Note that in an object return, the copy constructor gets called (if
defined). If the copy constructor is not defined, an exact copy of the
object is returned.

Not "exact", memberwise, which does whatever the members' copy
constructors say it does.
An object copy can result in hard to debug memory allocation issues.
Consider the case where the object being copied contained pointers to
dynamically allocated memory.

Then you should have either defined an appropriate copy constructor (and
probably a copy assigment operator and destructor), or disabled copying.
Don't blame the user if you provide him with a fundamentally broken
class.
Only the pointers would be copied. Thus
both objects would be pointing to the same allocated memory.

Return by reference can result in hard to debug pointer issues.
Consider the case where instead of a copy, you return a dangling
reference to a local variable which has gone out of scope and been
deleted. Thus the non-reference refers to a non-object which is
not-pointing to some not-allocated memory. If you'd only returned a
properly-constructed copy, none of this would have happened.
 
Y

Yannick Tremblay

In C++ returning an object is suitable only when the object contains
only a few data members. Returning an object results in a copy of
entire object thus it can have really impact performance if objects
with a large list of data members is returned.

This is incorrect, what you are suggesting is:
a) premature optimisation
b) optimisable by your compiler (google NRVO)
c) in most situation false (measure it!)

With optimisation turned on,

std::vector<someType> computeLargeVector();
std::vector<someType> v = computeLargeVector();

is going to be as fast if not faster as:

void computeLargeVector(std::vector<someType> &v);
std::vector<someType> v;
computeLargeVector(v);

(1st might be faster because the default constructor for vector will never
be called). Test and measure!
Note that in an object return, the copy constructor gets called (if
defined). If the copy constructor is not defined, an exact copy of the
object is returned.

Any object for which the default compiler-generated copy constructor
is not suitable should either be made:
a) explicitely non-copyable
b) have a valid copy-constructor supply (and assigment...)
An object copy can result in hard to debug memory allocation issues.
Consider the case where the object being copied contained pointers to
dynamically allocated memory. Only the pointers would be copied. Thus
both objects would be pointing to the same allocated memory.

That is correct if you have an invalid copy constructor but that's a
bug in your class, you should fix the class rather than promote
obfuscating practices.

Yan
 
M

Micah Cowan

Richard Herring said:
In message

[...]
In C++ returning an object is suitable only when the object contains
only a few data members. Returning an object results in a copy of
entire object thus it can have really impact performance if objects
with a large list of data members is returned.

You're recommending premature optimisation, which is never a good
idea. If _measurement_ indicates that this copy has an impact on
performance, _then_ consider an alternative.

Preemptive optimization is not the same thing as premature
optimization (not all of the former are the latter). The latter
usually involves small-gain optimizations. Choosing good algorithms,
and making obviously smart decisions, are examples of the former that
are not in the latter set.

Are you seriously claiming that you never use a reference as return
type for performance reasons only, unless you've first tried it by
value and verified what you already knew to be true: that it's
significantly more efficient to return the reference (for objects
other than those that contain "only a few data members")?
 
D

Daniel T.

Are you seriously claiming that you never use a reference as return
type for performance reasons only, unless you've first tried it by
value and verified what you already knew to be true: that it's
significantly more efficient to return the reference (for objects
other than those that contain "only a few data members")?

What is seriously being claimed is that your comment above, (that it's
significantly more efficient to return the reference) is not generally
true.
 
M

Micah Cowan

Daniel T. said:
What is seriously being claimed is that your comment above, (that it's
significantly more efficient to return the reference) is not generally
true.

Okay, that's fair; however, it _is_ generally true that returning a
reference will be a constant-time operation (on reasonable
implementations, lack of such a guarantee in the Standard
notwithstanding, though one could probably be inferred from the
complexity constraints on container operations), whereas such is not
generally true (only allowed, which I had not realized) for returning
non-reference types.
 
R

Richard Herring

Micah Cowan said:
Richard Herring said:
In message

[...]
In C++ returning an object is suitable only when the object contains
only a few data members. Returning an object results in a copy of
entire object thus it can have really impact performance if objects
with a large list of data members is returned.

You're recommending premature optimisation, which is never a good
idea. If _measurement_ indicates that this copy has an impact on
performance, _then_ consider an alternative.

Preemptive optimization is not the same thing as premature
optimization (not all of the former are the latter). The latter
usually involves small-gain optimizations. Choosing good algorithms,
and making obviously smart decisions, are examples of the former that
are not in the latter set.

Indeed. That involves distinguishing between value and entity types, and
asking yourself why you would be writing functions that return large
value objects in the first place.
Are you seriously claiming that you never use a reference as return
type for performance reasons only,

I can't recall any occasion where I've used a reference as a return type
_at all_, except for e.g.:
- chainable functions like operator<< which return the same entity that
was passed in,
- assignment operators etc. which return *this.
- operator* in iterator or proxy classes, which returns the
thing-in-question.

And in those cases the reasons are always semantic, not
performance-related.
unless you've first tried it by
value and verified what you already knew to be true: that it's
significantly more efficient to return the reference (for objects
other than those that contain "only a few data members")?

I never seem to find myself writing functions that return value objects
containing huge numbers of data members, so the question doesn't arise.
 
J

James Kanze

Richard Herring said:
In message
[...]
In C++ returning an object is suitable only when the object contains
only a few data members. Returning an object results in a copy of
entire object thus it can have really impact performance if objects
with a large list of data members is returned.
You're recommending premature optimisation, which is never a good
idea. If _measurement_ indicates that this copy has an impact on
performance, _then_ consider an alternative.
Preemptive optimization is not the same thing as premature
optimization (not all of the former are the latter). The latter
usually involves small-gain optimizations. Choosing good algorithms,
and making obviously smart decisions, are examples of the former that
are not in the latter set.
Are you seriously claiming that you never use a reference as return
type for performance reasons only, unless you've first tried it by
value and verified what you already knew to be true: that it's
significantly more efficient to return the reference (for objects
other than those that contain "only a few data members")?

The discussion here regards what should be the "default"
behavior of the programmer. I don't have any problem with the
idea that one might hesitate before returning an
std::list<SomeObjectWithALotOfStrings>, if you know in advance
that the list will usually contain a couple of million elements,
and the call will take place in an inner loop. Such cases are
very, very rare, however, and I regularly return std::vector
from functions, without thinking about it.

The discussion was also about whether to return a reference or
not. If there is a performance problem returning a value such
as the above, the usual alternative is NOT to return a
reference, but to require the user to construct an empty
std::list, and pass a non const reference to it as an argument.
 
J

James Kanze

The below rules cover most situations for both parameters and return
values.
Returning by const reference is an optimization over returning by
value that you can use when you know that the object returned will
outlive the function returning it, the caller will not likely be
making a copy of its own, but be sure to let the caller know (through
documentation) how long that reference will be good for.
Returning by non-const reference is only for special situations where
the object being returned is either something that the caller has
access to anyway (for example returning a reference parameter that was
passed in, or a global,) or something that the function is
specifically designed to allow access to (for example containers, and
lazy initializers.)

Hmmm. I tend to return by reference when the object has
identity (and doesn't support copy). The simplest rule might
be: return by copy when you can, and by reference (or pointer)
when you must.
You may notice that I didn't mention pointers in the above,
they generally follow the same rules as references when you
are talking about the object the pointer points to, they
follow the same rules as objects when you are talking about
the pointer object *itself*.

Pointers may also be used for "fallible" values in some cases,
e.g. returning a null pointer if object lookup fails. But this
only works if the usual, successful return, as determined above,
would have been a reference. Otherwise, I think returning a
Fallible<T> is a clearer solution.
 
D

Daniel T.

Hmmm. I tend to return by reference when the object has
identity (and doesn't support copy). The simplest rule might
be: return by copy when you can, and by reference (or pointer)
when you must.

That would be a simpler rule, but I don't work that way. Obviously, if
the object doesn't support copy semantics then you have to return by
reference. Otherwise, I see returning by const reference as purely an
optimization issue. I write my code so that a return by object can be
changed to a return by const-reference by just changing the function
return and recompiling (assuming of course that the thing returned was
a copy of some long lived data in the first place.) Then I change it
to a const reference return if usage patterns indicate that most
clients don't need their own copy of the object returned.
 
J

James Kanze

That would be a simpler rule, but I don't work that way. Obviously, if
the object doesn't support copy semantics then you have to return by
reference. Otherwise, I see returning by const reference as purely an
optimization issue.

Which means you have to:). More generally, if it is important
that the client code see the actual instance, and not a copy,
you have to--the code won't work otherwise. This is probably
why even the const versions of std::vector<>::eek:perator[] return
a reference---so that if the client does something like:

int const* p = &v ; // v is a std::vector<int>,
// referenced through a const lvalue.

*p will reveal the last value written, and not the value at the
time operator[] was called. (In this case, of course, you have
to, because otherwise, there would be an unnecessary difference
compared to arrays.)
I write my code so that a return by object can be changed to a
return by const-reference by just changing the function return
and recompiling (assuming of course that the thing returned
was a copy of some long lived data in the first place.)

That's a good policy in general. For client code, at least.
Then I change it to a const reference return if usage patterns
indicate that most clients don't need their own copy of the
object returned.

And if the profiler says that the copy makes a difference, I
suppose.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,534
Members
45,008
Latest member
Rahul737

Latest Threads

Top