std::array的移动构造不发生深拷贝,而是根据元素类型决定行为:平凡可移动类型用memcpy,非平凡类型逐元素移动,无移动构造时退化为拷贝;移动后源对象处于有效但未指定状态。

不会。std::array 的移动构造函数不发生深拷贝,它本质上是按字节复制(memcpy-like)或逐元素移动,具体取决于元素类型是否 trivially_move_constructible。
std::array 移动构造的底层行为取决于元素类型
std::array 是聚合类型,不含动态资源,它的“移动”不是传统意义上的所有权转移,而是编译器对内部固定大小数组的优化处理:
- 若元素类型是
trivially_move_constructible(如int、double、POD struct),移动构造等价于std::memcpy—— 无构造/析构调用,纯内存搬运,O(1) 时间 - 若元素类型有非平凡移动构造函数(如
std::string、std::unique_ptr),则会逐个调用其T(T&&),但仍是移动而非拷贝 - 若元素类型没有移动构造函数(比如只定义了拷贝、且被
= delete了移动),则移动构造退化为拷贝构造(编译期报错或隐式回退,取决于上下文和标准库实现)
std::array(std::move(x)) 不改变 x 的值语义,但对象状态未定义
标准规定:对 std::array 调用移动构造后,源对象 x 处于“有效但未指定状态”(valid but unspecified state)。这不是 bug,而是标准对聚合类型的宽松要求:
- 对
int元素的std::array,多数实现下x内存内容不变(因为 memcpy 不改源),但你不该依赖这点 - 对
std::string元素的std::array,每个std::string都会被单独移动,所以x[0]可能为空,x[1]可能为空……但顺序和是否为空不保证 - 别在移动后访问
x的任何成员,哪怕只是x.size()—— 它返回固定模板参数,不读内存,但其他访问(如x[0])可能触发未定义行为
为什么 std::array 移动构造看起来“没效果”?
常见困惑:打印 std::array<int> a = {1,2,3}; auto b = std::move(a);</int> 后,a 还是 {1,2,3}。这是因为:
-
int是 trivial 类型,移动即复制,源内存未被清零或修改 -
std::array没有析构逻辑,也不管理堆内存,所以“移动”不涉及置空指针等操作 - 这和
std::vector或自定义类完全不同——后者移动后必须把data设为nullptr,否则析构时 double-free - 你看到的“没变”,是正确行为,不是失效;但依然不能假设它一定保持原值
真正容易被忽略的是:std::array 的移动是否生效,完全由其元素类型决定;写泛型代码时,别假设 std::move(arr) 一定比拷贝快——如果元素是大 struct 且没声明 noexcept 移动构造,编译器可能干脆不用移动。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











