#include <iostream>

struct A
{
    A( int ii ) : i(ii) { std::cout << "constructor i == " << i << '\n' ; }

    A( const A& that ) : i(that.i)
    { std::cout << "copy constructor i == " << i << '\n' ; }

    ~A() { std::cout << "destructor i == " << i << '\n' ; }

    A( A& that ) : i(that.i)
    { std::cout << "move constructor i == " << i << '\n' ; }

    A& operator= ( const A& that )
    { i = that.i ; std::cout << "copy assignment i == " << i << '\n' ; return *this ; }

    A& operator= ( A&& that )
    { i = that.i ; std::cout << "move assignment i == " << i << '\n' ; return *this ; }

    int i ;
};

A operator+ ( const A& a, const A& b )
{
    A temp( a.i + b.i ) ; // RVO applies, constructing 'temp'
    return temp ; // and then copying temp is elided
    // the function directly constructs the return value, 'temp' is elided
}

int main()
{
    A a(6) ; // constructor i == 6
    A b(8) ; // constructor i == 8
    A c(0) ; // constructor i == 0
    std::cout << "------------------------------\n" ;

    c = a+b ; // call operator+(a,b), RVO applies
    // step one:
    // construct anonymous temporary 'in place' - constructor i == 14
    // no copy or move constructor is involved

    // step two:
    // assign the anonymous temporary returned by operator+ to c
    // move assignment i == 14

    // step three:
    // destroy the anonymous temporary returned by operator+
    // destructor i == 14
    std::cout << "------------------------------\n" ;

    a.i = 100 ;
    b.i = 56 ;

    A d = a+b ; // call operator+(a,b), RVO applies
    // this function returns a prvalue ("pure rvalue")
    // a prvalue need not be associated with any object, it can be elided
    // therefore, construct d 'in place'
    // construct d - constructor i == 156
    // no copy or move constructor is involved
    std::cout << "------------------------------\n" ;

    std::cout << "press enter to destroy 'a', 'b', 'c' and 'd' and then quit\n" ;
    std::cin.get() ;

    // destroy d - destructor i == 156
    // destroy c - destructor i == 14
    // destroy b - destructor i == 56
    // destroy a - destructor i == 100
}
