The compiler will not elide the construction of a copy via clone()
: copy elision is only allowed in very specific situations. In all cases where the compiler is allowed to do copy elision the life-times of the objects involved are entirely controlled by the compiler. The four situations are (for details see 12.8 [class.copy] paragraph 8):
- Returning a local name by value.
- Throwing a local object.
- Copying a temporary object which isn't bound to a reference.
- When catching by value.
The details when copy-elision is applicable even in these situations are somewhat non-trivial. In any case, return new T(*this);
doesn't fit any of these situations.
Typical big objects don't hold their data as part of the object. Instead, they typically hold some data structures which can be moved. If you want to retain the simplicity when using A{f()}
without wanting to copy the result of f()
, you can get away with a move constructor calling a virtual
function transferring the content instead of copying it:
#include <utility>
class BigBaseClass {
public:
virtual ~BigBaseClass() {}
virtual BigBaseClass* clone() const = 0;
virtual BigBaseClass* transfer() && = 0;
};
class A{
BigBaseClass *ptr;
public:
A(BigBaseClass&& obj): ptr(std::move(obj).transfer()) {}
A(BigBaseClass const& obj): ptr(obj.clone()) {}
~A(){delete ptr;}
};
class BigDerivedClass
: public BigBaseClass {
BigDerivedClass(BigDerivedClass const&); // copy the content
BigDerivedClass(BigDerivedClass&&); // transfer the content
BigDerivedClass* clone() const { return new BigDerivedClass(*this); }
BigDerivedClass* transfer() && { return new BigDerivedClass(std::move(*this)); }
};
BigDerivedClass f() {
return BigDerivedClass();
}
int main()
{
A a{f()};
}
Whether move construction does help copying the big objects does depend on how the objects are internally implemented. If they object essentially just contains a couple of pointers to the actual large data, move construction should avoid any relevant cost as transferring the pointers would be negligible compared to setting up the actual data. If the data is actually held within the object the transfer wouldn't really help (although it is generally a bad idea to so anyway for a variety of reasons).