new[] 配合手动 realloc 是最直接的扩容方式;需申请新内存、复制旧数据、释放旧内存,注意检查 nullptr、更新长度、避免悬空指针,并按 1.5× 或 2× 增长以减少频繁分配。

new[] 配合手动 realloc 是最直接的扩容方式
用 new[] 分配原始数组后,c++ 没有内置“扩容”操作;必须申请新内存、复制旧数据、释放旧内存。这不是语法糖,是显式内存管理的必然步骤。
常见错误现象:std::bad_alloc(申请失败)、越界读写(忘了更新长度变量)、悬空指针(释放后还用原指针)。
- 每次扩容建议按 1.5× 或 2× 增长,避免频繁分配(如从 10 扩到 11,性能极差)
- 复制必须用
std::memcpy或循环赋值,不能直接operator=(原生数组不支持) - 务必检查
new是否返回nullptr(尤其在异常禁用时)
示例:把 arr 从 size 扩到 new_size
int* new_arr = new int[new_size]; std::memcpy(new_arr, arr, size * sizeof(int)); delete[] arr; arr = new_arr;
vector 是唯一推荐的“动态数组”替代方案
手写扩容逻辑极易出错,且无法自动处理构造/析构(比如 std::String 成员)。除非嵌入式场景明确禁用 STL,否则直接用 std::vector。
立即学习“C++免费学习笔记(深入)”;
使用场景:需要 push/pop、随机访问、跨函数传递、含非 POD 类型的容器。
-
std::vector::reserve()只改容量不改大小,不会触发元素构造 -
std::vector::resize()改大小,会默认构造新增元素(对 int 是 0,对 string 是空串) - 迭代器失效:
push_back可能导致所有迭代器失效(扩容时)
别用 vector.data() 后长期持有指针——扩容后地址就变了。
realloc 不适用于 C++ 对象数组
realloc 是 C 函数,只做内存块搬移,**完全跳过构造和析构函数调用**。对 std::string、std::vector 等类型,会导致资源泄漏或二次析构崩溃。
错误现象:double free or corruption、segmentation fault、字符串内容乱码。
- 仅当数组元素是 POD 类型(如
int、Float、纯 C Struct)时,realloc才安全 - 即便如此,也得确保原内存由
malloc分配(new分配的不能传给realloc) - 现代 C++ 工程中,混用
malloc/new是严重设计异味
自定义类里模拟动态数组要管好三件事
如果真要封装(比如教学或特殊内存池),核心不是“怎么扩容”,而是“谁负责生命周期”。漏掉任一环节都会崩。
- 析构函数必须
delete[] data_,否则内存泄漏 - 拷贝构造函数和
operator=必须深拷贝(否则两个对象共用一块内存) - 移动构造函数要置空源对象的
data_和size_,防止析构时重复释放
容易被忽略的点:扩容时若元素类型有非平凡析构函数(比如含 std::mutex),复制必须调用拷贝构造,不能 memcpy。