如何防止临时对象的创建?

时间:2013-06-11 02:54:28

标签: c++

我的代码类似于:

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

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

我的问题是createInstance()创建了一个稍后删除的临时文件。就我而言,它不使用RVO,我必须使用The Rule of Three(因为我的类有一个指向数据成员的指针),我必须做一个兆字节数据的深层复制。 我想知道什么是防止临时创建的最佳方法?

此外,我将此MyClass作为另一个类的成员,我想阻止指针的间接指令以及在我的父类的析构函数中手动删除它的要求。

例如,我可以使用指针代替(这需要我显式调用析构函数:

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

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

或者我可以使用成员函数:

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

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

或者我一般不允许分配/复制:

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

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

我错过了什么吗?

2 个答案:

答案 0 :(得分:3)

您不能将(N)RVO复制到预先存在的对象中。优化是关于使用另一个新创建的对象而不是复制,但在这种情况下,编译器不能保证赋值对象不会单独留下某些现有状态(例如)。

我希望MyClass primary(createInstance());可以为您启用NRVO。

如果您确实需要从创建函数分配,您的选择至少为两个:您可以创建临时然后交换,避免数据复制。或者使用C ++ 11,您可以move进入现有对象。

答案 1 :(得分:0)

就像稻田说的那样,你怎么知道它不使用RVO? 如果代码不在调试模式下,编译器将做很多事情来优化代码。 但是,在您的creatInstance函数中,您创建一个本地对象,并在其上调用成员函数。调用成员函数(t-> setValue(20))使得难以优化,因为编译器会认为,本地对象比返回值更有用。显然,我们知道可以优化本地t,但编译器可能无法从其上下文中分析它。

并且,通过“creatInstance”的含义,您似乎只想创建一个实例并将其返回。因此,如果您的构造允许直接设置值,则可以使用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
}

你可能会认为,它仍然需要创建临时对象__temp并将其销毁,是的,但是在原始代码中,你将创建两个临时对象并销毁它们,一个在你的主堆栈框架中,一个在你的creatInstance函数的堆栈中帧。

如果你不能承受创建临时对象和那些东西的成本,我想你可以改变你的想法:

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!

毕竟,你只想通过调用一个函数来改变主要内容,为什么不像上面那样直接写它?