提问人:muaz 提问时间:6/29/2022 更新时间:7/5/2022 访问量:203
std::move 是让堆栈碎片化,还是在将对象移动到调用方后重新排列堆栈?
Does std::move leave stack fragmented or is the stack rearranged after moving an object to the caller?
问:
我已经阅读了几个答案和许多关于移动语义的文章,所以它只是一个静态转换到右值引用,这个问题是关于它对堆栈的影响,那么堆栈在移动后是否留下了碎片?还是以某种方式重新排列?由于堆栈移动的对象不受堆栈展开的影响。以下代码片段运行良好:
#include <memory>
#include <cassert>
struct A {
int x = 0;
};
struct B {
A a;
};
void SetB(B& b) {
A a1{6}; //pushing into the stack.
A a2{7}; //pushing into the stack.
b.a = std::move(a2);
}
int main()
{
B b;
SetB(b);
assert( b.a.x == 7);
}
a2
在堆栈帧中定义,但在完成并返回 contorl 后仍然可用。然而; 是不是更接近堆叠框架?SetB
SetB
main
a1
main
答:
6赞
lorro
6/29/2022
#1
C++标准中没有“堆栈”,它是一个实现细节。因此,“通用”答案是困难的,因为实现可能会对给定架构的堆栈产生任何影响。
也就是说,它不会从堆栈中删除参数,它仍然处于有效但未定义的状态。对于您自己的类,您甚至可以实现它。因此,不可能从任何地方“删除”变量 - 当然,除非在编译器的优化阶段,如果它不再被访问。std::move()
a2
完成后不可用。该值被移动到 因此,应包含之前包含的值,但它不是相同的变量(也不是相同的内存地址)。SetB
b.a
b.a
a2
评论
0赞
muaz
6/29/2022
预期如何包含值,该值是否从堆栈帧复制到一个中?所以 std::move 不是那么便宜的操作吗?b.a
a2
SetB
main
0赞
Goswin von Brederlow
6/29/2022
std::move
实际上什么也没做。它只会影响编译器在编译过程中看到的类型。移动分配可以做一些工作。
0赞
lorro
6/30/2022
@muaz 纯粹是推测性的,你可能来自语言背景(可能是 PHP、Java),或者只是一种思维方式,对变量的赋值工作方式不同。在某些语言中,写作会创建一个“数字对象”,变量只引用它。c++ 并非如此 - 在 c++ 中,您的变量具有地址,并且变量的值(存储在给定地址上)会更新,而不是变量的“目标”会更新。该原理图存在,但它是指针(在这种情况下会不必要地变慢)。7
0赞
muaz
6/30/2022
#2
有了这个答案,我想总结一下我得到的所有信息,这些信息确实回答了我的问题:
- 对于堆栈中分配的所有变量,默认执行正常复制(如果这些变量很大,则非常昂贵),这是我在 JaMit、user17732522 和 lorro 回答后测试的。最初这个问题是因为虽然编译器会添加一些措施来管理堆栈而不复制所有内容,但看起来我高估了(没有堆栈碎片或重新排列,只有复制)。所以在上面的例子中,if的定义如下:
move
move
A
struct A {
int x[1000] = {};
};
移动会导致按原样复制整个数组。A
- 移动堆资源完全取决于程序员,程序员将转换为右值引用,一旦在 CTOR 中分配或调用,它将调用移动赋值或移动构造函数,如果这些是默认的,它会对指针进行浅拷贝,这可能会导致由于悬空指针而导致分段错误。
move
评论
SetB
a1
a2
A
std::move