How safe is returning a value by reference?

Discussion in 'C++' started by davidkevin@o2.pl, Jul 28, 2012.

  1. Guest

    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 someclear examples which will show when it is unsafe? Stroustrup has given in TC++PL among others following sample:

    class Matrix {
    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.

    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.
    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.

    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 like that:

    Matrix a, b;
    Matrix c;
    c=a+b;

    If operator+ returns a value by value then that value is returned by returnthis ; inside operator+ definition. Then a compiler can directly assign c to newly created object.

    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).

    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?

    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;

    Matrix& give_matrix_tem() {
    static int nbuf = 0;
    static Matrix buf[max_matrix_tem] nbuf = 0;
    return buf[nbuf++];
    }

    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+. But when an assignment to give_matrix_tem should be executed? What should be assigned to 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?

    Thanks in advance for responses,
    Greetings.
     
    , Jul 28, 2012
    #1
    1. Advertising

  2. On 7/28/2012 2:23 PM, 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:
    >
    > class Matrix { 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.
    >
    > 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. 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.

    > 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
    > like that:
    >
    > 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
    addition. So, no copying is involved. 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.

    > 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.

    > 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;
    >
    > Matrix& give_matrix_tem() { static int nbuf = 0; static Matrix
    > buf[max_matrix_tem] nbuf = 0; return buf[nbuf++]; }


    Something is not right in that code. A semicolon seems missing somewhere.

    > 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.

    > But when an assignment to give_matrix_tem should be executed?


    Some time inside the op+ after you got the 'res' reference.

    > What
    > 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...

    V
    --
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Jul 28, 2012
    #2
    1. Advertising

  3. Guest

    W dniu sobota, 28 lipca 2012 23:15:15 UTC+2 użytkownik Victor Bazarov napisał:
    > On 7/28/2012 2:23 PM, 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:

    >
    > >

    >
    > > class Matrix { 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.

    >
    > >

    >
    > > 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. 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?).


    The above text is taken from "The C++ Programming Language", Seventh Edition, chapter 11.6 (Operator overloading: Large objects). I had that book before my eyes when I was writing my post. But it it is not rewritten a character to a character - I have a polish edition.

    >(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.


    Understand I things proper that it means that in the situation in which I have
    a variable which was declared in method m() I can not return a reference tothat object? (It seems to me that more complex situations could lead to such error but that example has only show about what the problem is).

    >(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..


    OK. But how returning the reference to the static object can make that re-entrant will not be safe?

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

    >
    > > like that:

    >
    > >

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


    Yes, I have made a terrible mistake. I did mean a situation in which a new
    object is returned (which is a sum of a and b).

    > > 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.


    I want to know if returning a reference make it possible to improve an efficiency of calculations in instructions like:

    c=a+b;

    In other words: if we have instructions:

    c=a+b; //operator+ returns by a value
    f=d+e; //operator+ returns by a reference

    will one of those more efficient than other? For me it seems that not. In
    fist case return instruction inside operator+ will make that one copy of object will be created. When the assignment will be executed a next copy has not be created because a+b is temporary so we can use it directly (and I think that every good compiler will not make that unnecessary copy). In second case a value is returned by a reference so object is not copied here. Butcopy has to be executed in order to make the assignment possible.
    So in both cases one copy is created. So there is no reason for which one version should be more efficient than other. Am I right?

    > > 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.


    Have I used a word "capacity" incorrectly? What I mean was that returning areference has no impact for efficiency.

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

    >
    > >

    >
    > > Matrix& give_matrix_tem() { static int nbuf = 0; static Matrix

    >
    > > buf[max_matrix_tem] nbuf = 0; return buf[nbuf++]; }

    >
    >
    >
    > Something is not right in that code. A semicolon seems missing somewhere..


    const int max_matrix_tem = 7;

    Matrix& give_matrix_tem() {
    static int nbuf = 0;
    static Matrix buf[max_matrix_tem] nbuf = 0;
    if (nbuf==max_matrix_tem) nbuf = 0; //missed line
    return buf[nbuf++];
    }

    > > 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.
    >
    >
    >
    > > But when an assignment to give_matrix_tem should be executed?

    > Some time inside the op+ after you got the 'res' reference.


    > > What
    > > 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...


    That conception (using a buffer of static objects) is still not very clear for me. What is a reason for which operator+ know that give_matrix_tem willgive him an object which it that operator really needs?
     
    , Jul 29, 2012
    #3
  4. James Kanze Guest

    On Saturday, July 28, 2012 10:15:15 PM UTC+1, Victor Bazarov wrote:
    > On 7/28/2012 2:23 PM, 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:


    > > class Matrix
    > > {
    > > 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
    reference.)

    > > 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
    needed.

    > > 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
    > > like that:


    > > 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
    > addition.


    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;
    > >
    > > Matrix& give_matrix_tem()
    > > {
    > > static int nbuf = 0;
    > > static Matrix buf[max_matrix_tem] nbuf = 0;
    > > return buf[nbuf++];
    > > }


    > 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
    disappointed.

    (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
    multithreaded environment.

    > > But when an assignment to give_matrix_tem should be executed?


    > Some time inside the op+ after you got the 'res' reference.


    > > What
    > > 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...


    --
    James
     
    James Kanze, Jul 29, 2012
    #4
  5. SG Guest

    Am Sonntag, 29. Juli 2012 10:30:30 UTC+2 schrieb (unbekannt):
    > [...]
    > The above text is taken from "The C++ Programming Language", Seventh
    > Edition, chapter 11.6 (Operator overloading: Large objects). I had
    > that book before my eyes when I was writing my post. But it it is
    > not rewritten a character to a character - I have a polish edition.
    >
    > > (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.


    Right.

    > Understand I things proper that it means that in the situation in
    > which I have a variable which was declared in method m() I can not
    > return a reference to that object?


    If it's an _automatic_ object (an object stored in the automatic memory in the scope of the function) it will cease to exist once the execution returns to the caller. Returnung a reference to this object is pointless since you cannot access it anymore through that reference outside the function because the object does not exist anymore.

    > > (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.


    Well, you "can" do lots of things. But you should not because most of it does not make sense and/or is a bad idea.

    > OK. But how returning the reference to the static object can make
    > that re-entrant will not be safe?


    Sorry, what?

    > [...]
    > I want to know if returning a reference make it possible to improve
    > an efficiency of calculations in instructions like:
    >
    > c=a+b;
    >
    > In other words: if we have instructions:
    >
    > c=a+b; //operator+ returns by a value
    >
    > f=d+e; //operator+ returns by a reference
    >
    > will one of those more efficient than other? For me it seems that
    > not. In fist case return instruction inside operator+ will make
    > that one copy of object will be created.


    What copy do you mean?

    > When the assignment will
    > be executed a next copy has not be created because a+b is
    > temporary so we can use it directly (and I think that every good
    > compiler will not make that unnecessary copy).


    This does not make sense to me. First, you say a copy has to be created then you say that a decent compiler will optimize it away. There is nothing a compiler can do about assignments. If you have an assignment, the appropriate operator= function gets excecuted. That's it.

    > In second case a
    > value is returned by a reference so object is not copied here.
    > But copy has to be executed in order to make the assignment possible.
    >
    > So in both cases one copy is created. So there is no reason for which
    > one version should be more efficient than other. Am I right?


    In my opinion, efficiency matters little if the "faster" version is not re-entrant or cannot be used in a multi-threaded environment or even returns dangling references.

    > const int max_matrix_tem = 7;
    >
    > Matrix& give_matrix_tem() {
    > static int nbuf = 0;
    > static Matrix buf[max_matrix_tem] nbuf = 0;
    > if (nbuf==max_matrix_tem) nbuf = 0; //missed line
    > return buf[nbuf++];
    > }


    Please don't ever write horrible code like this.

    If you're concerned about efficiency, please look elsewhere. For example:
    - move semantics
    - copy on write.
    - expression templates (lazy evaluation)

    Cheers!
     
    SG, Jul 29, 2012
    #5
  6. James Kanze Guest

    On Sunday, July 29, 2012 9:30:30 AM UTC+1, (unknown) wrote:
    > W dniu sobota, 28 lipca 2012 23:15:15 UTC+2 użytkownik Victor Bazarov napisał:


    > > On 7/28/2012 2:23 PM, wrote:


    [...]
    > The above text is taken from "The C++ Programming Language",
    > Seventh Edition, chapter 11.6 (Operator overloading: Large
    > objects). I had that book before my eyes when I was writing my
    > post. But it it is not rewritten a character to a character -
    > I have a polish edition.


    Don't. Regretfully, translations of technical books are almost
    always miserable, and frequently misleading. Stroustrup is one
    of the rare authors who understands the problem, and does what
    he can to fix it, when he is made aware of it. But globally,
    you're better off struggling in English with the original. You
    won't have to deal with misleading translations, and when you do
    post a question in an English speaking forum, you'll be able to
    use the correct vocabulary, instead of trying to guess the
    original word that the translator translated with whatever in
    your language. And of course, the more you read in English,
    the less you'll have to struggle.

    (I really regret having to give this advice, because I think you
    should be able to use your own language. But the reality is
    that you can't.)

    > >(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.


    > Understand I things proper that it means that in the situation
    > in which I have a variable which was declared in method m() I
    > can not return a reference to that object? (It seems to me
    > that more complex situations could lead to such error but that
    > example has only show about what the problem is).


    I think you need some clarification with regards to the language
    you're using. All *objects* have a specific lifetime. (A
    variable is a name bound to an object.) If you define a
    non-static variable with local scope (within a block of code),
    the object has something known as "automatic" lifetime, which
    means it ceases to exist when the name goes out of scope.
    (Unless, of course, the variable has reference type, in which
    case, with one major exception which doesn't concern us here, it
    has no effect on the object lifetime.)

    A reference is not an object, but creates another way of
    referring to an existing object. If the lifetime of the
    reference exceeds that of the object, you have a dangling
    reference. Which is undefined behavior---another way of saying
    that anything might happen.

    > >(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.


    > OK. But how returning the reference to the static object can
    > make that re-entrant will not be safe?


    In more complicated expressions, like "(a+b) * (c+d)", the
    return value of "a+b" and of "c+d" refer to the same object. If
    the two return values are supposed to have different values, one
    of them will have been overwritten when you get to the *
    operator.

    > I want to know if returning a reference make it possible to
    > improve an efficiency of calculations in instructions like:


    > c=a+b;


    It might, or it might not. In the general case, if copying a
    Matrix is expensive, it probably will improve efficiency. At
    the cost of giving incorrect results in more complicated
    expressions.

    > In other words: if we have instructions:


    > c=a+b; //operator+ returns by a value
    > f=d+e; //operator+ returns by a reference


    > will one of those more efficient than other? For me it seems
    > that not. In fist case return instruction inside operator+
    > will make that one copy of object will be created. When the
    > assignment will be executed a next copy has not be created
    > because a+b is temporary so we can use it directly (and I
    > think that every good compiler will not make that unnecessary
    > copy). In second case a value is returned by a reference so
    > object is not copied here. But copy has to be executed in
    > order to make the assignment possible.


    The assignment will still copy. On the other hand, the return
    value will not be copied from any local variable.

    Most compilers today implement some form the return value
    optimization, which will avoid the copy in well written code.
    (In at least one compiler, "well written code" means no more
    than a single return statement in the function.)

    > So in both cases one copy is created. So there is no reason
    > for which one version should be more efficient than other. Am
    > I right?


    Without the return value optimization, return by value would
    result in a copy in the function; the return value will be
    copied from a local variable or a temporary into where ever the
    compiler puts class type return values. (The memory used for
    local variables typically disappears when you return from the
    function.) The return value optimization means that this copy
    is suppressed.

    [...]
    > > > 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;


    > Matrix& give_matrix_tem() {


    > static int nbuf = 0;
    > static Matrix buf[max_matrix_tem] nbuf = 0;


    There's still too much on the preceding line.

    > if (nbuf==max_matrix_tem) nbuf = 0; //missed line
    > return buf[nbuf++];
    > }


    > That conception (using a buffer of static objects) is still
    > not very clear for me. What is a reason for which operator+
    > know that give_matrix_tem will give him an object which it
    > that operator really needs?


    Don't worry about it. It's an advanced technique, to be learned
    only after you've mastered the basic lifetime issues. The basic
    rule is:

    -- return a reference when you want to allow access to data
    held by your object (e.g. something like the operator[] on a
    vector).

    -- return a value in all other cases.

    -- pass class types by reference to const, all other types by
    value.

    -- and don't use references anywhere but in the above cases.

    That's sufficient for all but the most advanced programmers. (I
    can't remember the last time I did anything else, and I've 30
    years experience in C++, much of it in very low level,
    performance oriented code.)

    --
    James
     
    James Kanze, Jul 29, 2012
    #6
  7. Guest

    OK, thanks to all for the discussion, every post was valuable for me but last post by James Kanze make things completely clear and I have understood already how the technique of buffering static objects could help in the improvement of calculations efficiency.

    BTW: James Kanze, I believe that a book which you described as a "book for beginners" is "Programming: Principles and Practice using C++" but it isn'tone which I use now. The book which I read is "The C++ Programming Language". It is the fact that Stroustrup has shown a sample of the technique mentioned above but he explicitly stated that if somebody will write an expression which would require more temporary variables than max_matrix_tem then he is asking about enter into real troubles.

    Greetings.
     
    , Jul 30, 2012
    #7
  8. James Kanze Guest

    On Monday, July 30, 2012 8:19:03 AM UTC+1, (unknown) wrote:

    > BTW: James Kanze, I believe that a book which you described as a "book for
    > beginners" is "Programming: Principles and Practice using C++"


    That's the one I was referring to. If you've no great
    experience programming, it's by far the best book I've seen for
    starting.

    > but it isn't
    > one which I use now. The book which I read is "The C++ Programming Language".


    That's an excellent reference, but it's more oriented to
    advanced programmers (IMHO, anyway).

    > It is the fact that Stroustrup has shown a sample of the technique mentioned
    > above but he explicitly stated that if somebody will write an expression
    > which would require more temporary variables than max_matrix_tem then he is
    > asking about enter into real troubles.


    Yes. Stroustrup tends to understand these sort of things. It's
    a useful technique in certain restricted contexts. It was also
    much abused in earlier days (before RVO and NRVO were well
    known).

    --
    James
     
    James Kanze, Jul 30, 2012
    #8
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Gabriel Rossetti
    Replies:
    0
    Views:
    1,401
    Gabriel Rossetti
    Aug 29, 2008
  2. Replies:
    1
    Views:
    378
    Brian Candler
    Aug 12, 2003
  3. Aredridel

    Not just $SAFE, but damn $SAFE

    Aredridel, Sep 2, 2004, in forum: Ruby
    Replies:
    19
    Views:
    266
  4. Farrel Lifson

    $SAFE =4 safe enough?

    Farrel Lifson, Aug 29, 2006, in forum: Ruby
    Replies:
    7
    Views:
    121
    Eric Hodel
    Aug 31, 2006
  5. JustMe
    Replies:
    1
    Views:
    190
    Tassilo v. Parseval
    Aug 29, 2003
Loading...

Share This Page