3

我有类似这样的代码:

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

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

我的问题是createInstance()创建了一个临时的,稍后会被删除。就我而言,它不使用 RVO,我必须使用三法则(因为我的类有一个指向数据成员的指针),并且我必须对兆字节数据进行深度复制。我想知道防止临时创建的最佳方法是什么?

此外,我将此 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();
}

我错过了什么吗?

4

2 回答 2

3

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

我希望这MyClass primary(createInstance());将为您启用 NRVO。

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

于 2013-06-11T03:59:37.570 回答
0

就像 paddy 说的,你怎么知道它没有使用 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!

毕竟,你只是想通过调用一个函数来改变primary,为什么不像上面那样直接写呢?

于 2013-06-11T03:35:54.940 回答