Re: How safe is returning a value by reference?
On Saturday, July 28, 2012 10:15:15 PM UTC+1, Victor Bazarov wrote:
On 7/28/2012 2:23 PM, email@example.com wrote:
Hi, I have seen an interesting example of applications of returning a
value by reference from method. But is it really safe? If not could
you give me some clear examples which will show when it is unsafe?
Stroustrup has given in TC++PL among others following sample:
friend Matrix& operator+(const Matrix&, const Matrix&);
He have claimed that above code is proper but it causes problems with
memory allocation. I am not sure what he means.
I think you (the original poster) have slightly misunderstood.
The above code is "correct", in that it doesn't violate any of
the syntactic rules of C++. It's not correct because of
lifetime of object issues; the reference you return refers to an
object which ceases to exist when you return.
He has stated that: 1. a reference to a result will be passed outside
the function as a reference to a value passed from a function, so
that value can't be an automatic variable.
I'm sure he expressed it more clearly than that. The returned
reference refers to a local variable, which ceases to exist once
you've left the function. (This is called a dangling
2. Operator is often used
in an expression more than once so it can't be a local static
variable. 3. Copying a passed value is usually cheaper (with respect
to time of execution, size of code and size of data).
I would like to know what are reasons for which above sentences
holds. Again, I would be grateful for clear examples.
The (1) seems convoluted too much (did you re-type it from any of his
books, by memory?). (1) You cannot return a reference to an automatic
object because by the time you get to use that reference, the object has
been already destroyed. (2) You cannot return a reference to a static
object inside the op+ function because the function could be used more
than once in the same expression, and hence needs to be safely re-entrant.
Reentrant isn't really the word which corresponds, since
reentrant refers to being in the same function several times at
once. But I can't find a good word to specify the quality
Next - Stroustrup claim that passing by reference could cause an
improvement of efficiency (however his third from above statements
shows that not necessarily). Ok, but I wonder what happens in code
Matrix a, b; Matrix c; c=a+b;
If operator+ returns a value by value then that value is returned by
return this ; inside operator+ definition. Then a compiler can
directly assign c to newly created object.
If operator+ has a 'this' to return, it's a non-static member function,
yes? To be that it has to have only one explicit argument, the
right-hand side of the + expression, yes? Then what does it change, the
left-hand side? IOW, in the expression a+b, the matrix 'a' will be
changed? That's absurd.
So, conclusion then is that operator+ cannot 'return this'. It can only
be a friend function or a const member function that *still* returns a
new object, but not 'this'.
If operator+ returns a value by a reference then a copy has to be
created - in other case c would be a same object which a+b is. But
syntax of the assignment denies it - a reference is nothing other
than a synonym for an object so above instruction has to mean that a
value is assigned (and not object).
Can you rephrase that? I have hard time following your thought.
There are certain things you might want to read up on. First, RVO
(return value optimization). The expression c=a+b causes two (usually)
function calls, op+ and op=. If op+ returns a temporary, then the
compiler could optimize away the call to op= to actually use the 'c'
object as the place where the temporary is created for the result of the
Not in this case (assignment). The c object has already been
constructed, so the compiler cannot use it for another object
which will be newly constructed.
So, no copying is involved.
No copy construction is involved. The compiler cannot optimize
away copy assignment (or at least, not easily).
Second, perhaps you should get
familiar with C++0x feature called "move assignment", which could help
in this case, giving another way for the compiler to optimize away
copying if it's not necessary since the object *from* which the contents
are copied during the assignment, is temporary and doesn't have to survive.
Introducing move semantics at the point where the original
poster is may be a bit premature. They're an advanced
technique, which can be ignored by most programmers.
So as far as I understand when an assignment or an initialization is
executed returning a value by a reference has no impact for capacity.
Am I right?
What's "impact for capacity"? Please define that before I can answer
your "am I right" question.
He seems to be inventing a special vocabulary of his own.
Replace "capacity" by "storage" or "storage duration", and it
makes a little more sense.
Later, Stroustrup has given an example of the technique about which
he has said that it causes that a result is not copied:
const int max_matrix_tem = 7;
static int nbuf = 0;
static Matrix buf[max_matrix_tem] nbuf = 0;
Something is not right in that code. A semicolon seems missing somewhere.
I'd guess that the second "nbuf = 0" is noise, and shouldn't be
there. Without it, this was a classic technique to avoid deep
copy of return values. It's also a very dangerous techique: it
works for up to 7 (in this case) return values, and then fails
in a difficult to detect manner. (Difficult to detect, because
the failure only occurs in complex expressions, where one of the
return values sometimes gets overwritten.)
This is a technique which should only be used with extreme
caution, in very restricted contexts, by programmers who really
know what they're doing. If Stroustrup actually recommends this
in his recent book (the one for beginners), then I'm a bit
(The technique can result in a significant improvement in
performance. But there are other techniques which can be used
to avoid the copy as well.)
Matrix& operator+(const Matrix& arg1, const Matrix& arg2)
Matrix& res = give_matrix_tem();
//... return tem;
As far as I understand above code should help to improve efficiency
if we have an expression in which there is more than one operator+.
Yes, a temporary storage is used for the result of op+. That storage is
allocated once and reused, in hopes that none of functions that make use
of that storage are called in some expressions more than 7 times.
And in the hopes that the code will never be used in a
But when an assignment to give_matrix_tem should be executed?
Some time inside the op+ after you got the 'res' reference.
should be assigned to give_matrix_tem?
Nothing. You should think of terms of 'res' when implementing the op+
function that uses 'give_matrix_tem'.
It looks that in the situation
in which buf is full filled a value which give_matrix_tem() will
return next will be old one. And how above code make that a copying
of value is avoided?
Returning a reference to an existing object does not involve copying.
Since 'res' in op+ is a reference to an existing storage object (one of
the elements of the 'buf' array), no copying happens. Or maybe I don't
understand what you're asking...