You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

memmove覆盖对象及其生命周期相关技术问题

关于memmove处理可平凡复制对象的生命周期疑问

memmove允许源地址与目标地址存在重叠区域。若将其用于trivially copyable类型,memmove复制的对象会被隐式创建,其生命周期随之启动(不存在未定义行为)。但针对memmove覆盖对象的场景,存在以下疑问,先看示例代码:

#include <array>
#include <type_traits>
#include <iostream>

struct obj_t {
    int a, b, c, d;
};

static_assert(std::is_trivially_copyable_v<obj_t> == true,
    "objects must be trivially copyable to be implicitly created by memmove");

int main() {

    std::array<obj_t, 8> objs{};

    std::cout << "before:\n";
    int i = 0;
    for (auto& obj : objs) {
        obj.a = i++;
        std::cout << obj.a << "\n";
    }

    //move 4 objects from position 2 to position 1 in the array:
    obj_t* src  = &objs[2];
    obj_t* dest = &objs[1];
    memmove(dest, src, 4 * sizeof(obj_t));

    std::cout << "after:\n";
    for (auto& obj : objs) std::cout << obj.a << "\n";
}

程序输出如下:

before:
0
1
2
3
4
5
6
7
after:
0
2
3
4
5
5
6
7

数组中位置1至4的结构体被覆盖(包含重叠区域与非重叠区域的部分结构体)。

问题

  • 被memmove覆盖的对象,其生命周期会如何变化?在新对象被隐式创建前,它们的生命周期是否会正常结束(此处是否存在未定义行为)?
  • 对于源地址处遗留的重复副本(如位置5的结构体),旧副本是否仍属于活跃对象?

解答

问题1:被覆盖对象的生命周期与未定义行为

当用memmove覆盖trivially copyable类型的对象时,旧对象的生命周期会在新对象被隐式创建的那一刻终止,不存在“新对象创建前旧对象还活跃”的阶段,因此这里没有未定义行为。

C++标准规定,对于可平凡复制类型,当你通过字节复制(比如memmove)将数据写入某个存储位置时,若该位置原本有同类型对象,字节复制的行为会直接隐式创建新对象并覆盖旧对象——旧对象的生命周期会被新对象的创建自动终结,不需要显式销毁(因为可平凡复制类型的销毁不需要执行特殊逻辑)。

在示例中,objs[1]到objs[4]这些旧对象,在memmove执行过程中被字节覆盖时,对应的新对象会被隐式创建,旧对象的生命周期同步结束,全程符合标准要求,没有未定义行为。

问题2:源地址遗留副本的活跃性

源地址中被复制但未被覆盖的对象(比如示例中的objs[5]),其生命周期依然保持活跃。

memmove只是读取源地址的字节数据进行复制,这个操作不会影响源对象的生命周期——只要源对象所在的存储位置没有被覆盖,也没有被显式销毁,它就还是活跃的对象。示例中objs[5]的字节数据被复制到了objs[4],但objs[5]自身的存储位置没有被修改,所以它仍然是原来的那个活跃对象,后续对它的访问依然合法。

内容的提问来源于stack exchange,提问作者greenlagoon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 10:48:11