non-const reference to temporary object

Discussion in 'C++' started by rajath575@gmail.com, Nov 27, 2008.

  1. Guest

    I encountered a problem when passing temporary variable as a non const
    variable. The message was " initial value of reference to non-const
    must be an lvalue "

    void foo(MyClass &Var)
    {
    // Whatever
    }

    foo(MyClass());

    What is the exact problem here?
    Does it have to do anything with the scope of the temporary MyClass
    passed to the function? What is its scope?
    And how does changing the declaration of foo as void foo(const MyClass
    &Var) change anything?
    , Nov 27, 2008
    #1
    1. Advertising

  2. Rolf Magnus Guest

    wrote:

    > I encountered a problem when passing temporary variable as a non const
    > variable.


    Not exactly. It's not about passing it to a function, but about binding it
    to a reference.

    > The message was " initial value of reference to non-const
    > must be an lvalue "
    >
    > void foo(MyClass &Var)
    > {
    > // Whatever
    > }
    >
    > foo(MyClass());
    >
    > What is the exact problem here?


    C++ doesn't allow binding a temporary to a non-const reference.
    Rolf Magnus, Nov 27, 2008
    #2
    1. Advertising

  3. Salt_Peter Guest

    On Nov 26, 11:00 pm, wrote:
    > I encountered a problem when passing temporary variable as a non const
    > variable. The message was " initial value of reference to non-const
    > must be an lvalue "
    >
    > void foo(MyClass &Var)
    > {
    > // Whatever
    >
    > }
    >
    > foo(MyClass());
    >
    > What is the exact problem here?
    > Does it have to do anything with the scope of the temporary MyClass
    > passed to the function? What is its scope?


    Scope is not the same as lifetime, scope refers to an object's
    visibility.
    A temporary's lifetime is ephemeral unless it is kept alive somehow.

    > And how does changing the declaration of foo as void foo(const MyClass
    > &Var) change anything?


    It changes everything.
    Myclass() generates a temporary with a lifetime limited to its short
    existance.

    Myclass& r = MyClass(); // temporary is born and dies here
    // accesing r is now undefined behavior

    a const reference extends the lifetime of the temporary

    const Myclass& r_ = MyClass(); // temp is born and is kept alive
    // r_ is still valid here
    // the temporary stays valid until r_'s lifetime ends

    your example above does exactly the same thing:

    ....
    void foo(const MyClass& r_val)
    {
    // r_val is still valid here
    }
    Salt_Peter, Nov 27, 2008
    #3
  4. Kai-Uwe Bux Guest

    Salt_Peter wrote:

    > On Nov 26, 11:00 pm, wrote:
    >> I encountered a problem when passing temporary variable as a non const
    >> variable. The message was " initial value of reference to non-const
    >> must be an lvalue "
    >>
    >> void foo(MyClass &Var)
    >> {
    >> // Whatever
    >>
    >> }
    >>
    >> foo(MyClass());
    >>
    >> What is the exact problem here?
    >> Does it have to do anything with the scope of the temporary MyClass
    >> passed to the function? What is its scope?

    >
    > Scope is not the same as lifetime, scope refers to an object's
    > visibility.


    True.

    > A temporary's lifetime is ephemeral unless it is kept alive somehow.


    In the case from above, that is immaterial. The temporary lives until the
    end of the full expression, which would be long enough for the call to
    foo() to complete. One can see this by cheating a little:

    #include <iostream>
    #include <ostream>

    struct MyClass {

    MyClass ( void ) {
    std::cout << "constructed\n";
    }

    ~MyClass ( void ) {
    std::cout << "destroyed\n";
    }

    MyClass & me ( void ) {
    return ( *this );
    }

    };

    void foo ( MyClass & obj ) {
    std::cout << "call to foo\n";
    }

    int main ( void ) {
    foo ( MyClass().me() ), std::cout << "even later than foo\n";
    }

    This prints:

    constructed
    call to foo
    even later than foo
    destroyed


    [snip]

    To the OP:

    The reason lies in the standard [8.5.3/5], which explicitly prevents
    initializing a non-const reference from a temporary. Nonetheless, calling
    non-const member functions on temporaries is fine (see the me() function
    above). Thus:

    std::vector<int> iv;
    std::vector<int>().swap( iv ); // ok
    iv.swap( std::vector<int>() ); // not ok


    The following trick is not standard conforming, but I think it will be with
    C++0X:

    template < typename T >
    T & lvalue_cast ( T const & ref ) {
    return( const_cast< T & >( ref ) );
    }

    With that, you could do:

    foo( lvalue_cast( MyClass() ) );



    Best

    Kai-Uwe Bux
    Kai-Uwe Bux, Nov 27, 2008
    #4
  5. James Kanze Guest

    On Nov 27, 6:18 am, Salt_Peter <> wrote:
    > On Nov 26, 11:00 pm, wrote:


    > > I encountered a problem when passing temporary variable as a
    > > non const variable. The message was " initial value of
    > > reference to non-const must be an lvalue "


    > > void foo(MyClass &Var)
    > > {
    > > // Whatever
    > > }


    > > foo(MyClass());


    > > What is the exact problem here?
    > > Does it have to do anything with the scope of the temporary
    > > MyClass passed to the function? What is its scope?


    > Scope is not the same as lifetime, scope refers to an object's
    > visibility.


    To a symbols visibility. Scope doesn't concern objects, but
    symbols (and it's purely a lexical concept, not runtime---except
    when language rules associate lifetime with scope).

    > A temporary's lifetime is ephemeral unless it is kept alive
    > somehow.


    A temporary's lifetime is until the end of the full expression,
    normally.

    > > And how does changing the declaration of foo as void
    > > foo(const MyClass &Var) change anything?


    > It changes everything. Myclass() generates a temporary with a
    > lifetime limited to its short existance.


    > Myclass& r = MyClass(); // temporary is born and dies here
    > // accesing r is now undefined behavior


    > a const reference extends the lifetime of the temporary


    I think you're missing the point. First, the language rules
    don't allow initializing a reference with an rvalue unless it is
    a reference to a non-volatile const type. That's what's causing
    his error. (There is one exception: if the rvalue is a class
    type with a user defined conversion to an lvalue type, it is
    treated as an lvalue, and the conversion is used.) Lifetime
    simply isn't a consideration here. The second point (not
    relavent to his example) is that if a reference is initialized
    with a temporary, the lifetime of that temporary is extended to
    match the lifetime of the reference. This really has nothing to
    do with const, except that the situation can't be reached unless
    the reference is to a non-volatile const. (This is, IMHO, a
    fairly tricky point, and irrelevant to most code anyway.)

    > const Myclass& r_ = MyClass(); // temp is born and is kept alive
    > // r_ is still valid here
    > // the temporary stays valid until r_'s lifetime ends


    > your example above does exactly the same thing:


    No it doesn't. In his case, the lifetime of the temporary is
    until the end of the full expression. Longer than the lifetime
    of the temporary it initializes. And none of the special rules
    ever reduces the lifetime of a temporary.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Nov 27, 2008
    #5
  6. James Kanze Guest

    On Nov 27, 6:39 am, Kai-Uwe Bux <> wrote:
    > Salt_Peter wrote:
    > > On Nov 26, 11:00 pm, wrote:
    > >> I encountered a problem when passing temporary variable as
    > >> a non const variable. The message was " initial value of
    > >> reference to non-const must be an lvalue "


    > >> void foo(MyClass &Var)
    > >> {
    > >> // Whatever
    > >> }


    > >> foo(MyClass());


    > >> What is the exact problem here?
    > >> Does it have to do anything with the scope of the temporary
    > >> MyClass passed to the function? What is its scope?


    > > Scope is not the same as lifetime, scope refers to an
    > > object's visibility.


    > True.


    False. In some ways, it seems like a nit, but we are talking
    about vocabulary, and it's an important distinction. Scope does
    not have anything to do with objects; it is a property of a
    symbol. Talking about the scope of an unnamed temporary has no
    meaning. And objects can be visible through several different
    symbols (that's what references are for), each with different
    scope.

    [...]
    > The following trick is not standard conforming, but I think it
    > will be with C++0X:


    > template < typename T >
    > T & lvalue_cast ( T const & ref ) {
    > return( const_cast< T & >( ref ) );
    > }


    > With that, you could do:


    > foo( lvalue_cast( MyClass() ) );


    Why isn't it conforming?

    The real question is why he wants to bind the temporary to a
    non-const reference. There are several legitimate uses, but
    each has a somewhat different effective work-around.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Nov 27, 2008
    #6
  7. Kai-Uwe Bux Guest

    James Kanze wrote:
    > First, the language rules
    > don't allow initializing a reference with an rvalue unless it is
    > a reference to a non-volatile const type. That's what's causing
    > his error. (There is one exception: if the rvalue is a class
    > type with a user defined conversion to an lvalue type, it is
    > treated as an lvalue, and the conversion is used.)


    Just to elaborate on the parenthetical remark, the type of the lvalue must
    be different from the type of the rvalue, i.e., the following should not
    compile:

    struct X {

    int x;

    X ( int i = 0 )
    : x ( i )
    {}

    operator X & ( void ) const {
    return ( *this );
    }

    };

    void add_one ( X & ref ) {
    ++ ref.x;
    }

    #include <iostream>

    int main ( void ) {
    X const a ( 2 );
    add_one( a );
    std::cout << a.x << '\n';
    }

    The reason is that as per [12.3.2/1], the conversion cannot be called to
    convert an rvalue of type T to an lvalue of type T&.


    Best

    Kai-Uwe Bux
    Kai-Uwe Bux, Nov 27, 2008
    #7
  8. Kai-Uwe Bux Guest

    James Kanze wrote:

    ...]
    >> The following trick is not standard conforming, but I think it
    >> will be with C++0X:

    >
    >> template < typename T >
    >> T & lvalue_cast ( T const & ref ) {
    >> return( const_cast< T & >( ref ) );
    >> }

    >
    >> With that, you could do:

    >
    >> foo( lvalue_cast( MyClass() ) );

    >
    > Why isn't it conforming?


    Well, there are two issues with this code.

    (a) The standard allows copying (in a non-slicing manner) of the object
    while initializing the const reference. Therefore, the lvalue_cast<> might
    not yield a reference to the temporary created by MyClass() but to another
    temporary constructed therefrom by copy-construction.

    (b) Related but slightly different, the above assumes the existence of a
    copy constructor where none should be needed.

    For most code those points do not matter, of course. I would agree that
    non-conforming is probably not exact. However, the function name creates
    the impression that you would get a reference to the object passed in; and
    that is not guaranteed (but I think it will be).


    > The real question is why he wants to bind the temporary to a
    > non-const reference. There are several legitimate uses, but
    > each has a somewhat different effective work-around.


    In my opinion, we should not need the work arounds.



    Best

    Kai-Uwe Bux
    Kai-Uwe Bux, Nov 27, 2008
    #8
  9. Guest


    > The real question is why he wants to bind the temporary to a
    > non-const reference.  There are several legitimate uses, but
    > each has a somewhat different effective work-around.


    I was using a Symbian C++ macro to generate a descriptor
    ( temporary ) and was trying to write it to a file using a function
    which took a non-const parameter. Probably not the right place to
    discuss.
    Thanks to everyone who answered.
    , Nov 27, 2008
    #9
  10. James Kanze Guest

    On Nov 27, 10:22 am, Kai-Uwe Bux <> wrote:
    > James Kanze wrote:
    > [..]
    > >> The following trick is not standard conforming, but I think it
    > >> will be with C++0X:


    > >> template < typename T >
    > >> T & lvalue_cast ( T const & ref ) {
    > >> return( const_cast< T & >( ref ) );
    > >> }


    > >> With that, you could do:


    > >> foo( lvalue_cast( MyClass() ) );


    > > Why isn't it conforming?


    > Well, there are two issues with this code.


    > (a) The standard allows copying (in a non-slicing manner) of
    > the object while initializing the const reference. Therefore,
    > the lvalue_cast<> might not yield a reference to the temporary
    > created by MyClass() but to another


    Ah yes. I'd forgotten about that aspect.

    > (b) Related but slightly different, the above assumes the
    > existence of a copy constructor where none should be needed.


    Which is a bit of a bother, since some of the most useful cases
    involve classes which don't support copy (e.g. ostringstream).

    > For most code those points do not matter, of course. I would
    > agree that non-conforming is probably not exact. However, the
    > function name creates the impression that you would get a
    > reference to the object passed in; and that is not guaranteed
    > (but I think it will be).


    Yes. There has been some tightening down in that section.
    (IIRC, the requirement for a copy constructor is also being
    dropped.)

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Nov 27, 2008
    #10
  11. James Kanze Guest

    On Nov 27, 6:44 pm, wrote:
    > > The real question is why he wants to bind the temporary to a
    > > non-const reference. There are several legitimate uses, but
    > > each has a somewhat different effective work-around.


    > I was using a Symbian C++ macro to generate a descriptor (
    > temporary ) and was trying to write it to a file using a
    > function which took a non-const parameter. Probably not the
    > right place to discuss.


    Yes and no. The question in this case is why a function which
    writes the object to a file takes a non-const reference.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Nov 27, 2008
    #11
    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. =?ISO-8859-1?Q?Ney_Andr=E9_de_Mello_Zunion?=

    The temporary vs non-const reference love story

    =?ISO-8859-1?Q?Ney_Andr=E9_de_Mello_Zunion?=, Nov 4, 2003, in forum: C++
    Replies:
    13
    Views:
    582
    Ron Natalie
    Nov 6, 2003
  2. John Ky
    Replies:
    9
    Views:
    436
    John Ky
    Feb 23, 2004
  3. qazmlp
    Replies:
    4
    Views:
    1,392
    Buster
    May 6, 2004
  4. George2
    Replies:
    10
    Views:
    595
    Pete Becker
    Dec 17, 2007
  5. reppisch
    Replies:
    6
    Views:
    403
    Andrey Tarasevich
    May 6, 2008
Loading...

Share This Page