Reputation: 12514
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
Upvotes: 0
Views: 325
Reputation: 49289
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
Upvotes: 1
Reputation: 36597
RVO is among those things that the standard permits, but does not specifically require. That said, most modern compilers (at least, with appropriately optimisation settings enabled) will implement it. If you want a guarantee, however, you will need to read your compiler documentation.
Since the aim is to dynamically allocate an object anyway, I would simply change the example so the called function does dynamic allocation. Instead of (the OP's code);
BigObj fun()
{
BigObj b;
// presumably the point of fun() is that some initialisation
// of b occurs here
return b;
}
int main()
{
BigObj *pb = new BigObj(fun());
}
I would simply use
BigObj *fun()
{
BigObj *b = new BigObj;
// presumably the point of fun() is that some initialisation
// of *b occurs here
return b;
}
int main()
{
BigObj *pb = fun();
}
and eliminate the potential copying of a BigObj
all together. The only thing that is being copied around is the value of a pointer. The compiler therefore does not rely on presence of C++11 move constructors to optimise the above, since it avoids unnecessary creation and copying of objects, so this meets the OPs need to not use C++11.
Obviously, in either case, it would be good practice to match the usage of operator new with a corresponding operator delete.
Upvotes: 0