Search code examples
c++c++11pass-by-referencervalue-reference

How to keep object passed by rvalue reference alive without copy?


I am trying to pass Child as r-value to Parent and save it there without copying the Child.

Parent p{ Child{} };

cout << "----Done----" << endl;

And now the implementation:

class Child
{
public:
    Child() { cout << "Child: created" << endl; }

    ~Child() { cout << "Child: destroyed" << endl; }
};

class Parent
{
    // store as r-value ref
    Child&& child;

public:
    // pass by r-value ref and move
    Parent(Child&& c) :child(move(c))
    {
        cout << "Parent: created" << endl;
    }

    ~Parent() { cout << "Parent: destroyed" << endl; }
};

The output is:

Child: created
Parent: created
Child: destroyed
------Done------
Parent: destroyed

cppref says: Rvalue references can be used to extend the lifetimes of temporary objects

Question 1: Why isn't Child destroyed in the very end (or at least after Done)?
Question 2: How to make it live longer?

P.S:

Child& child;
...
Parent(Child c) :child(c)

Gives the exact same result.


Solution

  • cppref says: Rvalue references can be used to extend the lifetimes of temporary objects

    You are leaving out an important part of that quote. A more accurate quote is: "Rvalue references can be used to extend the lifetimes of temporary objects".

    Notice the difference? (Don't worry too much if you don't, as it is subtle.) There is a link to an explanation of how and when the lifetime of a temporary can be extended. You've tagged this question C++11, so the bullet point that is valid until C++14 applies:

    • a temporary bound to a reference member in a constructor initializer list persists only until the constructor exits, not as long as the object exists. (note: such initialization is ill-formed as of DR 1696).

    You bound a temporary to a reference member in a constructor initializer list. The temporary's lifespan is not extended beyond the end of the constructor. The temporary is destroyed before your object's destructor is called.


    How to make it live longer? That gets tricky, but if the parameter is always a temporary, you could make your member a non-reference and move the parameter to the member. If you want more flexibility, you may need to accept some copying.