2010-12-10 132 views
0

好吧,我一直在阅读有关rvalues,他们看起来像一个好主意,但有些事情一直在困扰着我。特别是移动的声明允许我们窃取资源并避免复制。rvalues C++ 0x and moving to stack

我知道移动的工作原理并避免复制堆栈上发生的所有事情,但最终在堆栈上完成的大部分工作产生了一些我们希望复制到堆中的值,这是我不认为的地方移动作品。

假设INT具有移动赋值运算符,给出下面的代码:

struct Foo 
{ 
int x; 
}; 

void doIt() 
{ 
Foo* f = new Foo(); 
f->x = (2 + 4); 
} 

因此,在此实例中,右值从(2 + 4)得到的推测可以被移动到F-> X代替的复制。好的,太好了。但f和因此f-> x在上,并且右值在堆栈上。似乎不可能避免复制。你不能简单地将f-> x指向右值的内存。一旦它结束,这个右值就会被吹走。副本似乎是必要的。

所以我是正确的,将复制副本? 还是我错了? 还是我完全误解了右值概念?

+1

看来你是误解了一些东西。移动不是魔术,没有比分配/复制更快的获取int值的方法。 – UncleBens 2010-12-10 15:56:09

+0

@UncleBens嗯,我只是想确认一下。我不断阅读右值使事情更快,避免复制。但正如在我的例子中,我试图确认复制确实是必需的,并且右值仅在某些特定情况下有所帮助。 – anio 2010-12-10 16:01:58

+0

标量类型的移动对象相当于复制它们。移动对于更复杂的类型变得有趣。如果您将这些事情发生在班级设计师身上,会发生什么。您可以通过定义您自己的移动构造函数来控制此行为。 – sellibitze 2010-12-10 20:48:43

回答

5

在这种情况下,它可能会做一个副本,但由于该对象只包含一个int,这不是什么大问题。

您关心的时间通常是当对象包含指向堆中分配的某些数据的指针(不管对象本身分配的位置)。在这种情况下,避免分配这些数据的新副本是非常值得的(因为即使对象本身在堆栈上,它也在堆上,无论对象本身位于何处,都可以移动它)。

+0

好点。移动可用于从一个堆位置窃取资源到另一个堆位置。所以我们可以进行堆栈到堆栈的移动。堆到堆的移动。但是没有堆栈到堆的移动。这是我的预期。 – anio 2010-12-10 15:04:37

+1

当然,您可以将堆栈中的对象堆叠起来,反之亦然。启用移动的类型通常不关心其移动的位置。存储的概念与移动语义是正交的。 – sellibitze 2010-12-10 20:56:12

1

嗯。局部变量在堆栈上。你的右值将被优化到6并且最终的二进制文件最有可能在其中有一个mov [dest], 6

3

我的理解是,移动不是复制相反:运动是可取的,因为在大多数情况下,将实施浅拷贝(而不是深拷贝)。

如果一个对象持有指向某个资源的指针,那么浅拷贝就是复制指针,而深度拷贝是复制指针指向的数据。总是有复制涉及:问题是“我们必须走多深”。

你举的例子只涉及一个int:有一个int的副本没有这样的事情,所以在这里无关紧要。所以确实,你相信只有在涉及动态分配的资源时,移动才有意义。

+0

移动当然不会*限于浅拷贝。这个构造函数的作用取决于你的类设计者。 – sellibitze 2010-12-11 15:38:32