Luxalpa
Luxalpa

Reputation: 430

How do I prevent the creation of temporary objects?

I have code similar to this:

MyClass createInstance() 
{
    MyClass t;
    t.setValue(20);
    return t;
}

int main()
{
    MyClass primary;
    primary.setValue(30);
    primary = createInstance();
}

My problem is that createInstance() creates a temporary that is deleted later. In my case, it doesn't use RVO, I have to use The Rule of Three (because my class has a pointer to data members), and I have to do a deep copy of Megabytes of data. I wonder what's the best way to prevent the creation of a temporary?

Furthermore, I have this MyClass as a member of another class and I would like to prevent the indirection of a pointer and the requirement to manually delete it in the destructor of my parent class.

For example, I could use pointers instead (which would require me to explicitly call the destructor:

MyClass *createInstance() 
{
    MyClass *t = new MyClass();
    t->setValue(20);
    return t;
}

int main()
{
    MyClass *primary = new MyClass();
    primary->setValue(30);
    delete primary;
    primary = createInstance();
}

Or I could use a member function:

void MyClass::createNewInstance()
{
    ~MyClass();
    init();
    setValue(20);
}

int main()
{
    MyClass primary;
    primary.setValue(30);
    primary.createNewInstance();
}

Or I could disallow Assignment/Copying in general:

void MyClass::createInstance()
{
    setValue(20);
}

int main()
{
    MyClass *primary = new MyClass();
    primary->setValue(30);
    delete primary;
    primary = new MyClass();
    primary->createInstance();
}

Am I missing something?

Upvotes: 3

Views: 1289

Answers (2)

Mark B
Mark B

Reputation: 96241

You can't (N)RVO copy into a pre-existing object. The optimization is all about using another freshly created object instead of copying, but in this case the compiler can't guarantee that the assignment object doesn't leave some of the existing state alone (for example).

I would expect that MyClass primary(createInstance()); would enable NRVO for you.

If you really need to assign from a create function your choices are at least two: You can create a temporary and then swap, avoiding the data copy. Alternately with C++11 you could move into the existing object.

Upvotes: 3

Zhiwei Chen
Zhiwei Chen

Reputation: 322

Just like what paddy said, how do you know it's not using RVO? The compiler will do many thing to optimize your code, if it's not in debugging mode. But, in your creatInstance function, you create a local object, and call a member function on it. The calling of the member function ( t->setValue(20) ) makes it difficult to be optimized, because the compiler will think, the local object is more useful than just an return value. Clearly, we know the local t can be optimized out, but the compiler may not be able to analyze this from its context.

And, by the meaning of "creatInstance", it seems that you just want creat an instance and return it. So, if your constuctor allows to set the value directuly, you can use the RVO:

MyClass creatInstance()
{
    return MyClass(20); // if your constuctor makes it possible
}
then, your code will be optimized to this:
// C++ psuedocode
void creatInstance(MyClass* ptr)
{
    new (ptr) MyClass(20);
}
int main()
{
   MyClass primary;
   primary.setValue(30);

   // primary = createInstance();
   MyClass __temp; // default constructor not called!
   creatInstance(&__temp);
   primary.operator=(__temp);
   // destruct the __temp
}

You may think, it still has to creat temporary object __temp and destroy it , yes, but in your original code, you will creat two temporary object and destroy them, one in your main stack frame, one in your creatInstance function's stack frame.

If you can not sustain the cost of creating temporary object and those stuff, I think you can just change your idea to this:

void  modifyInstance(Myclass&  objToBeModified)
{
     objToBeModified.setValue(20);
     // do any change
}
and call it by : modifyInstance ( primary );
by this way, the temporary object creation is definitely prevented!

After all, you just want to change the primary by calling a function, why not writting it directly like above?

Upvotes: 0

Related Questions