Search code examples
c++c++03rvonrvo

Does RVO work with "new"?


Does copy elision kick in in this situation? In other words, do modern compilers with copy elision avoid to call any copy constructor here?

class BigObj{};

BigObj fun()
{
  BigObj b;
  return b;
}
int main()
{
  BigObj *pb = new BigObj(fun());
}

I aim to store an object in a pointer. The object is returned by a function. I want to store it without copying it.

I can't use c++11


Solution

  • IMO it is not entirely clear what you aim to achieve. If dynamic allocation is what you want to use, then your function should simply:

    BigObj * fun()
    {
      return new BigObj;
    }
    int main()
    {
      BigObj *pb = fun();
    }
    

    ... and save yourself the trouble.

    Contrary to the previous revision of the answer, it turned out that the compiler can omit a substantial amount of work as long as it is in a static context that can be thoroughly analyzed:

    class C {
    public:
        C() {qDebug() << "C created";}
        C(const C & o) { qDebug() << "C copied"; }
    };
    
    C foo() {
        C c;
        qDebug() << &c;
        return c;
    }
    
    ...
        C c = C(foo()); // note that `C c = ` is also copy construction
        qDebug() << &c;
    

    The output verifies that both instances have the same address, so even in the context of a local, the instance is actually not stored in the stack frame of foo.

    Changing to:

    C * cp = new C(foo());
    qDebug() << cp;
    

    to my surprise also output the same address, with both the return by value copy and the copy constructor omitted. c in foo is constructed directly in the memory chunk, allocated by new.

    In conclusion the C++ compiler is pretty smart at analyzing and doing every possible optimization.

    Turning off optimizations in the first and second case respectively:

    C created
    0x28fd97
    C copied
    C copied
    C copied
    0x28fdeb
    
    ...
    
    C created
    0x28fd97
    C copied
    C copied
    0x34fd00