调用移动对象的成员函数是否可行?下述代码是否存在危险或未定义行为?
你的代码安全吗?拆解细节与风险边界
没问题,这段代码不存在未定义行为,但咱们得把核心逻辑和潜在注意点掰扯清楚:
先搞懂std::swap在这里的实际行为
你调用的std::swap(arr[i], arr[arr.size()-1]),交换的是vector里两个Bar元素的内容,而非元素的内存位置。vector的元素存在连续内存块里,只要不触发扩容(这里vector大小没变,肯定不会扩容),每个元素的内存地址是固定的——说白了,就是把两个Bar的x和parent成员互换了位置,对象本身在内存里的“座位”没动。
跟着调用链走一遍,看哪里会出问题?
咱们一步步捋:
- 你通过
foo.arr[3].trigger(3)调用trigger,此时函数里的this指针指向foo.arr[3]的内存地址。 trigger内部调用parent->moveBack(3),moveBack执行swap操作:- 这时候
foo.arr[3]这个地址上的对象内容,已经被换成了原来最后一个Bar的内容,但this指针还是死死盯着这个地址。
- 这时候
- 但关键来了:你的
trigger函数在调用完moveBack之后就直接返回了,再也没碰过this或者当前对象的任何成员。所以哪怕这个地址的对象内容被替换了,也不会有任何问题——因为我们已经用不上它了。
什么时候会踩坑?扩展逻辑时要注意
如果后续你给trigger加了代码,比如swap之后还要访问当前对象的成员:
void Bar::trigger(size_t i) { parent->moveBack(i); std::cout << this->x << std::endl; // 这里输出的是原来最后一个Bar的x,不是当前对象原本的x! }
这时候会出现逻辑错误(不是未定义行为),因为此时this指向的foo.arr[3]已经是另一个Bar的内容了。但你现在的代码里没有这个情况,所以完全安全。
关于“对象移动自身”的小误解
你提到“本质上是Bar类型的对象在移动自身”,其实更准确的说法是:对象的内容被交换到了vector的最后一个位置,而对象的内存地址(也就是this指向的位置)根本没动。vector的元素不会因为swap换座位,换的只是座位上的“乘客”(成员值)。
内容的提问来源于stack exchange,提问作者nitronoid
相关产品推荐
相关产品推荐

