好吧,我一直在阅读有关右手的内容,看起来这是个好主意,但有些东西一直困扰着我。特别是移动的主张允许我们窃取资源并避免复制。
我理解移动是有效的,并且确实避免复制堆栈上发生的所有事情,但最终在堆栈上完成的大部分内容会产生一些我们想要复制到堆中的值,这是我不认为移动的地方的工作原理。
假设int有一个移动赋值运算符,给定以下代码:
struct Foo
{
int x;
};
void doIt()
{
Foo* f = new Foo();
f->x = (2 + 4);
}
因此,在这个例子中,由(2 + 4)得到的右值可以推移到f-> x而不是复制。好,太棒了。但是f和因此f-> x在堆上,并且rvalue在堆栈上。似乎无法避免副本。你不能简单地将f-> x指向rvalue的内存。一旦它结束,那个右值就会被吹走。副本似乎是必要的。
我是否正确制作副本? 还是我错了? 或者我是否完全误解了右值概念?
答案 0 :(得分:5)
在这种情况下,它可能会复制一次,但由于该对象只包含int
,所以这并不是一个问题。
您关心的时间通常是当对象包含指向堆上分配的某些数据的指针时(无论对象本身的分配位置如何)。在这种情况下,避免分配该数据的新副本是非常值得的(因为即使对象本身在堆栈上,它也在堆上,无论对象本身位于何处,都可以移动它。)
答案 1 :(得分:3)
我的理解是移动不是复制的反面:移动是首选,因为在大多数情况下它会实现浅拷贝(而不是深复制)。
如果一个对象持有指向某个资源的指针,则浅拷贝正在复制指针,而深拷贝正在复制指针指向的数据。总是涉及复制:问题是“我们必须走多远”。
您的示例只涉及int
:没有int的浅或深副本,因此这里无关紧要。事实上,你认为移动只有在涉及动态分配的资源时才有意义。
答案 2 :(得分:1)
庵。局部变量在堆栈中。您的rvalue将优化为6
,生成的二进制文件很可能会包含mov [dest], 6
。