Copy Constructor And Temporary Objects

Discussion in 'C++' started by Marcelo De Brito, Mar 1, 2009.

  1. Hi!

    I have stumbled upon an interesting feature when passing objects "by
    value" to functions. Let's say I have the following class:

    class Class1 {
    public:
    Class1();
    ~Class1();
    };

    And I have two functions that deal with objects from that class:

    Class1 func1()
    {
    Class1 x;
    return(x);
    }

    void func2(Class1& aa)
    {
    }

    So, my objective is passing the return value of "func1" as an argument
    to "func2", but doing this directly does not work, that is:

    func2(func1()); //!ERROR

    BUT, if I define the argument of "func2" as a "const Class1&" type --
    that is, "func2(const Class1&)" --, then, no error occurs when calling
    "func2(func1())".

    Why does that happen?

    What is the problem with the line "func2(func1())" ?

    Thank You!

    Marcelo
    Marcelo De Brito, Mar 1, 2009
    #1
    1. Advertising

  2. Marcelo De Brito

    Ivan Guest

    On 3ÔÂ1ÈÕ, ÏÂÎç2ʱ00·Ö, Marcelo De Brito <> wrote:
    > Hi!
    >
    > I have stumbled upon an interesting feature when passing objects "by
    > value" to functions. Let's say I have the following class:
    >
    > class Class1 {
    > public:
    > Class1();
    > ~Class1();
    >
    > };
    >
    > And I have two functions that deal with objects from that class:
    >
    > Class1 func1()
    > {
    > Class1 x;
    > return(x);
    >
    > }
    >
    > void func2(Class1& aa)
    > {
    >
    > }
    >
    > So, my objective is passing the return value of "func1" as an argument
    > to "func2", but doing this directly does not work, that is:
    >
    > func2(func1()); //!ERROR
    >
    > BUT, if I define the argument of "func2" as a "const Class1&" type --
    > that is, "func2(const Class1&)" --, then, no error occurs when calling
    > "func2(func1())".
    >
    > Why does that happen?
    >
    > What is the problem with the line "func2(func1())" ?
    >
    > Thank You!
    >
    > Marcelo


    Because that function func1 return a temporary object and this object
    is a right-value.
    Function func2's parameter is Class1 &, a none-const reference. it can
    reference any left-value, but can't reference to right-value. Only
    const Class1 & type can reference right-value in the readonly
    behavior.

    In C++0x, the rvalue reference is introduced to address this issue.
    You can overload func2 to deal with temporary object as bellow:

    void func2(Class1 &&a)
    {
    ...
    }
    Ivan, Mar 1, 2009
    #2
    1. Advertising

  3. Marcelo De Brito

    Kai-Uwe Bux Guest

    Marcelo De Brito wrote:

    > Hi!
    >
    > I have stumbled upon an interesting feature when passing objects "by
    > value" to functions. Let's say I have the following class:
    >
    > class Class1 {
    > public:
    > Class1();
    > ~Class1();
    > };
    >
    > And I have two functions that deal with objects from that class:
    >
    > Class1 func1()
    > {
    > Class1 x;
    > return(x);
    > }
    >
    > void func2(Class1& aa)
    > {
    > }
    >
    > So, my objective is passing the return value of "func1" as an argument
    > to "func2", but doing this directly does not work, that is:
    >
    > func2(func1()); //!ERROR
    >
    > BUT, if I define the argument of "func2" as a "const Class1&" type --
    > that is, "func2(const Class1&)" --, then, no error occurs when calling
    > "func2(func1())".
    >
    > Why does that happen?


    Because clause [8.3.5/5] of the standard says so.


    > What is the problem with the line "func2(func1())" ?


    A non-const reference cannot be initialized from a temporary. The argument
    to func2 is a non-const reference. A const reference can be initialized
    from a temporary. Hence the modified version compiles cleanly.

    Comments:

    a) One rationale for this provision lies in the implicit conversion rules of
    C++. If you had a function

    void inc ( int & i ) {
    ++i;
    }

    and you would use inc on a parameter of type char, then a temporary of type
    int would be created. Now, incrementing that temporary is very likely not
    what you want.

    b) That temporaries cannot bind to non-const references might create the
    impression that temporaries are const. That is not the case: you can call
    non-const member functions on temporaries. This leads to some strange
    results:

    vector< int > iv;
    ...
    vector<int>().swap( iv ); // legal
    iv.swap( vector<int>() ); // illegal
    swap( iv, vector<int>() ); // illegal

    This sometimes presents a trap with streams since some instances of
    operator<< are member functions and some are free standing functions.

    c) C++0X will have not only have references but also rvalue references,
    which obey different rules.


    Best

    Kai-Uwe Bux
    Kai-Uwe Bux, Mar 1, 2009
    #3
    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. Andy Buckley
    Replies:
    5
    Views:
    333
    Victor Bazarov
    Aug 26, 2004
  2. Replies:
    5
    Views:
    347
    Victor Bazarov
    Jun 24, 2005
  3. rdc02271
    Replies:
    24
    Views:
    721
    Jacek Dziedzic
    Dec 27, 2005
  4. Generic Usenet Account
    Replies:
    10
    Views:
    2,202
  5. cinsk
    Replies:
    35
    Views:
    2,563
    James Kanze
    Oct 11, 2010
Loading...

Share This Page