Object lifetimes when bound to references

Discussion in 'C++' started by Matthias Kaeppler, Apr 2, 2005.

  1. Hello,

    during a discussion on a C++ internet forum, some question came up
    regarding references and the lifetime of the objects they alias.

    I can't find any clear wording on that in the draft standard. Example
    12.2 in the standard document illustrates that temporaries bound to
    references-to-const live as long as the reference does.
    But does it e.g. matter if the temporary was created in scope of a
    function body and has to outlive the function call? And what happens
    with this temporary when everything else from the stack has to be
    destroyed except the temporary? Is it copied to a new location in memory?

    Examples:

    int f1()
    {
    int a=1;
    return a;
    }

    int& f1r() // note that the return type changed
    {
    int a=1;
    return a;
    }

    int f2()
    {
    int a(1),b(2);
    return a+b;
    }

    int& f2r()
    {
    int a(1),b(2);
    return a+b;
    }

    ....
    /* 1 */ const int& ref = f1();
    /* 2 */ const int& ref = f1r();
    /* 3 */ const int& ref = f2();
    /* 4 */ const int& ref = f2r();
    /* 5-8 */ <like 1-4 but without const qualifier>

    Can you comment expressions 1-8 regarding their behavior (defined,
    undefined) and the lifetime of the objects which are aliased?

    Thanks a lot.

    --
    Matthias Kaeppler
    Matthias Kaeppler, Apr 2, 2005
    #1
    1. Advertising

  2. Matthias Kaeppler wrote:
    > I can't find any clear wording on that in the draft standard. Example
    > 12.2 in the standard document illustrates that temporaries bound to
    > references-to-const live as long as the reference does.


    That only refers to a temporary bound _directly_ to a const reference.

    > But does it e.g. matter if the temporary was created in scope of a
    > function body and has to outlive the function call?


    In a normal execution of the program, a temporary created in the body
    of a function cannot outlive the function call. The only way where
    a temporary created inside a function can outlive the function by
    having a reference bound to it is when an exception is thrown.

    > And what happens
    > with this temporary when everything else from the stack has to be
    > destroyed except the temporary? Is it copied to a new location in
    > memory?


    That's unspecified, IIRC.

    >
    > Examples:
    >
    > int f1()
    > {
    > int a=1;
    > return a;
    > }
    >
    > int& f1r() // note that the return type changed
    > {
    > int a=1;
    > return a;


    Undefined behaviour. You're returning a reference to a local variable.
    As soon as the function returns, the reference is invalid.

    > }
    >
    > int f2()
    > {
    > int a(1),b(2);
    > return a+b;
    > }
    >
    > int& f2r()
    > {
    > int a(1),b(2);
    > return a+b;


    Ill-formed. A reference to a non-const object is [attempted to be] bound
    to a temporary. Shall not compile (8.5.3/5).

    > }
    >
    > ...
    > /* 1 */ const int& ref = f1();
    > /* 2 */ const int& ref = f1r();
    > /* 3 */ const int& ref = f2();
    > /* 4 */ const int& ref = f2r();
    > /* 5-8 */ <like 1-4 but without const qualifier>
    >
    > Can you comment expressions 1-8 regarding their behavior (defined,
    > undefined) and the lifetime of the objects which are aliased?


    Cases 1 and 3 have const references bound to temporaries created as
    the result of functions returning an object. Those objects live as long
    as the references live (in the surrounding scope, which can be as broad
    as global). The temporaries are not actually created *inside* the
    function.

    All other cases either have undefined behavioir because you're returning
    a reference to a local object or ill-formed because a non-const reference
    cannot be bound to a temporary object.

    V
    Victor Bazarov, Apr 2, 2005
    #2
    1. Advertising

  3. Victor Bazarov wrote:
    > Matthias Kaeppler wrote:
    >
    >>I can't find any clear wording on that in the draft standard. Example
    >>12.2 in the standard document illustrates that temporaries bound to
    >>references-to-const live as long as the reference does.

    >
    >
    > That only refers to a temporary bound _directly_ to a const reference.
    >
    >
    >>But does it e.g. matter if the temporary was created in scope of a
    >>function body and has to outlive the function call?

    >
    >
    > In a normal execution of the program, a temporary created in the body
    > of a function cannot outlive the function call. The only way where
    > a temporary created inside a function can outlive the function by
    > having a reference bound to it is when an exception is thrown.
    >
    >
    >>And what happens
    >>with this temporary when everything else from the stack has to be
    >>destroyed except the temporary? Is it copied to a new location in
    >>memory?

    >
    >
    > That's unspecified, IIRC.
    >
    >
    >>Examples:
    >>
    >>int f1()
    >>{
    >> int a=1;
    >> return a;
    >>}
    >>
    >>int& f1r() // note that the return type changed
    >>{
    >> int a=1;
    >> return a;

    >
    >
    > Undefined behaviour. You're returning a reference to a local variable.
    > As soon as the function returns, the reference is invalid.
    >
    >
    >>}
    >>
    >>int f2()
    >>{
    >> int a(1),b(2);
    >> return a+b;
    >>}
    >>
    >>int& f2r()
    >>{
    >> int a(1),b(2);
    >> return a+b;

    >
    >
    > Ill-formed. A reference to a non-const object is [attempted to be] bound
    > to a temporary. Shall not compile (8.5.3/5).
    >
    >
    >>}
    >>
    >>...
    >>/* 1 */ const int& ref = f1();
    >>/* 2 */ const int& ref = f1r();
    >>/* 3 */ const int& ref = f2();
    >>/* 4 */ const int& ref = f2r();
    >>/* 5-8 */ <like 1-4 but without const qualifier>
    >>
    >>Can you comment expressions 1-8 regarding their behavior (defined,
    >>undefined) and the lifetime of the objects which are aliased?

    >
    >
    > Cases 1 and 3 have const references bound to temporaries created as
    > the result of functions returning an object. Those objects live as long
    > as the references live (in the surrounding scope, which can be as broad
    > as global). The temporaries are not actually created *inside* the
    > function.
    >
    > All other cases either have undefined behavioir because you're returning
    > a reference to a local object or ill-formed because a non-const reference
    > cannot be bound to a temporary object.
    >
    > V
    >
    >


    Alright, and what if I change the signature of f1r() to

    const int& f1r()

    and the signature of f2r() to

    const int& f2r()

    respectively?


    --
    Matthias Kaeppler
    Matthias Kaeppler, Apr 3, 2005
    #3
  4. Victor Bazarov wrote:
    > Matthias Kaeppler wrote:
    >
    >>I can't find any clear wording on that in the draft standard. Example
    >>12.2 in the standard document illustrates that temporaries bound to
    >>references-to-const live as long as the reference does.

    >
    >
    > That only refers to a temporary bound _directly_ to a const reference.
    >
    >


    Do you have the paragaph at hand which backs this statement?

    --
    Matthias Kaeppler
    Matthias Kaeppler, Apr 3, 2005
    #4
  5. Matthias Kaeppler wrote:
    > Victor Bazarov wrote:
    >> Matthias Kaeppler wrote:
    >>
    >>> I can't find any clear wording on that in the draft standard.
    >>> Example 12.2 in the standard document illustrates that temporaries bound
    >>> to
    >>> references-to-const live as long as the reference does.

    >>
    >>
    >> That only refers to a temporary bound _directly_ to a const
    >> reference.

    >
    > Do you have the paragaph at hand which backs this statement?


    12.2/5, I believe.

    The point of my statement is to say that

    const int & i = 5;
    const int & j = i;

    does not make the temporary '5' persist as long as 'j' lives, only as
    long as 'i' lives. IOW, the second initialisation is not "binding of
    a temporary to a reference".

    V
    Victor Bazarov, Apr 4, 2005
    #5
  6. Matthias Kaeppler wrote:
    > Victor Bazarov wrote:
    >> Matthias Kaeppler wrote:
    >>
    >>> I can't find any clear wording on that in the draft standard.
    >>> Example 12.2 in the standard document illustrates that temporaries bound
    >>> to
    >>> references-to-const live as long as the reference does.

    >>
    >>
    >> That only refers to a temporary bound _directly_ to a const
    >> reference.
    >>> But does it e.g. matter if the temporary was created in scope of a
    >>> function body and has to outlive the function call?

    >>
    >>
    >> In a normal execution of the program, a temporary created in the body
    >> of a function cannot outlive the function call. The only way where
    >> a temporary created inside a function can outlive the function by
    >> having a reference bound to it is when an exception is thrown.
    >>
    >>
    >>> And what happens
    >>> with this temporary when everything else from the stack has to be
    >>> destroyed except the temporary? Is it copied to a new location in
    >>> memory?

    >>
    >>
    >> That's unspecified, IIRC.
    >>
    >>
    >>> Examples:
    >>>
    >>> int f1()
    >>> {
    >>> int a=1;
    >>> return a;
    >>> }
    >>>
    >>> int& f1r() // note that the return type changed
    >>> {
    >>> int a=1;
    >>> return a;

    >>
    >>
    >> Undefined behaviour. You're returning a reference to a local
    >> variable. As soon as the function returns, the reference is invalid.
    >>
    >>
    >>> }
    >>>
    >>> int f2()
    >>> {
    >>> int a(1),b(2);
    >>> return a+b;
    >>> }
    >>>
    >>> int& f2r()
    >>> {
    >>> int a(1),b(2);
    >>> return a+b;

    >>
    >>
    >> Ill-formed. A reference to a non-const object is [attempted to be]
    >> bound to a temporary. Shall not compile (8.5.3/5).
    >>
    >>
    >>> }
    >>>
    >>> ...
    >>> /* 1 */ const int& ref = f1();
    >>> /* 2 */ const int& ref = f1r();
    >>> /* 3 */ const int& ref = f2();
    >>> /* 4 */ const int& ref = f2r();
    >>> /* 5-8 */ <like 1-4 but without const qualifier>
    >>>
    >>> Can you comment expressions 1-8 regarding their behavior (defined,
    >>> undefined) and the lifetime of the objects which are aliased?

    >>
    >>
    >> Cases 1 and 3 have const references bound to temporaries created as
    >> the result of functions returning an object. Those objects live as
    >> long as the references live (in the surrounding scope, which can be
    >> as broad as global). The temporaries are not actually created
    >> *inside* the function.
    >>
    >> All other cases either have undefined behavioir because you're
    >> returning a reference to a local object or ill-formed because a
    >> non-const reference cannot be bound to a temporary object.
    >>
    >> V
    >>
    >>

    >
    > Alright, and what if I change the signature of f1r() to
    >
    > const int& f1r()
    >
    > and the signature of f2r() to
    >
    > const int& f2r()
    >
    > respectively?



    As soon as the function returns and the full expression that contains
    that funciton call is evaluated, the temporary is going to be destroyed.
    So, in f1r a temporary will be created but will only live long enough
    to make it to the outside. A reference initialised from that reference
    ( /* 2 */ const int& ref = f1r(); ) is still going to be invalid (thus
    the program has undefined behaviour). The same with case 4.

    V
    Victor Bazarov, Apr 4, 2005
    #6
  7. Matthias Kaeppler wrote:
    > [...]



    Wanted to add that if you wrote

    const int& f2r() { int a(1), b(2); return a+b; }

    ...

    const int& ref = f2r() + 0;

    you would have a valid and definedly-behaved program because
    there would be another temporary created to which 'ref' is bound
    and that temporary would persist as long as 'ref' lives.

    V
    Victor Bazarov, Apr 4, 2005
    #7
    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. sunil panda

    Lower bound & Upper bound

    sunil panda, Dec 25, 2003, in forum: Java
    Replies:
    9
    Views:
    7,236
    thushara wijeratna
    Oct 7, 2008
  2. Rhiner Dan
    Replies:
    1
    Views:
    745
    Mike Wahler
    Mar 27, 2005
  3. Phillip Vong
    Replies:
    0
    Views:
    413
    Phillip Vong
    Jul 27, 2006
  4. James

    reference lifetimes...

    James, Nov 10, 2009, in forum: C++
    Replies:
    13
    Views:
    643
    James Kanze
    Nov 12, 2009
  5. Murray Hopkins
    Replies:
    6
    Views:
    111
    Murray Hopkins
    Feb 28, 2007
Loading...

Share This Page