memmove能安全处理内存重叠,因其内部先判断源目标地址关系:若dest > src且重叠则反向复制,否则正向复制,避免边读边覆写导致的数据污染。

memmove 为什么能安全处理内存重叠
memmove 的核心设计就是为内存重叠场景服务的。它内部会先判断源和目标区域是否重叠,再决定从高地址还是低地址开始拷贝:如果目标在源之后(即 dest > src 且有重叠),就从尾部反向复制;否则正向复制。这避免了 memcpy 那种“边读边覆写”导致的数据污染。
常见错误现象是:用 memcpy 移动同一数组内相邻块(比如把 arr[1] 到 arr[n-1] 左移一位),结果部分数据被提前覆盖,最终得到乱码或重复值。
什么时候必须用 memmove 而不是 memcpy
只要存在以下任一情况,就必须换用 memmove:
- 操作的是同一块动态分配的内存(如
char*指向的缓冲区)中的两个有交集的区间 - 对
std::vector底层数据做原地平移(例如通过&vec[0]获取指针后手动移动) - 实现自定义容器的
erase或insert,且不打算重建整个内存块 - 调用者无法静态保证
src和dest不重叠(比如函数接口暴露给外部传参)
memmove 的参数和典型误用
memmove 原型是 void* memmove(void* dest, const void* src, size_t n),三个参数顺序和 memcpy 一致,但语义更宽松。容易踩的坑包括:
- 传入空指针且
n > 0→ 行为未定义(和memcpy一样,不校验指针有效性) - 误以为
memmove会自动处理对象构造/析构 → 它只做字节搬运,对非 POD 类型(如含虚函数、引用成员的类)直接使用是未定义行为 - 混淆长度单位:第三个参数是字节数,不是元素个数;用
sizeof(T)乘错会导致截断或越界 - 在 C++ 中对
std::string或std::vector的 data() 直接调用memmove后没更新 size/capacity → 容器状态不一致,后续访问崩溃
示例(安全左移一个 int 数组):
int arr[5] = {1, 2, 3, 4, 5};
memmove(arr, arr + 1, 4 * sizeof(int)); // 正确:覆盖前已备份后续字节
// arr 现在是 {2, 3, 4, 5, 5}
memmove 在现代 C++ 中还值得用吗
多数场景下,优先用更高层抽象:比如 std::vector::erase、std::rotate、std::copy_backward。它们类型安全、可读性强,编译器也能优化成接近 memmove 的汇编。
但仍有不可替代的场合:
- 处理裸内存池(如网络包解析、嵌入式 DMA 缓冲区)
- 编写底层序列化/反序列化逻辑,需精确控制字节布局
- 兼容 C 接口或 legacy 系统,必须返回
void*并保持 ABI 稳定
注意:memmove 是 C 标准库函数,在 C++ 中需包含 ;链接时无需额外库,但某些 freestanding 环境可能不提供。
真正容易被忽略的是:即使你用了 memmove,也不代表解决了所有重叠问题——如果目标区域处于源对象的生命周期之外(比如源对象已被 delete),那仍是悬垂指针问题,和函数选型无关。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











