C++实现简单的动态数组 _ 手写Vector底层扩容逻辑【源码】

老萱小哥_7467

老萱小哥_7467

2026-04-09

330人浏览

原创

扩容必须分配新内存并逐个移动/拷贝构造,因vector底层为连续原始缓冲区,new[]无法就地延展,realloc不适用于非平凡类型;直接memcpy会导致string等类型双释放或悬垂指针。

c++实现简单的动态数组 _ 手写vector底层扩容逻辑【源码】

扩容时为什么必须用 malloc + memcpy 或 new + 手动拷贝?

因为 std::vector 的底层内存是连续的原始缓冲区,没有“就地扩容”这回事。C++ 的 new[] 分配的是固定大小的堆块,无法像 realloc 那样尝试原地延展(且 realloc 也不适用于含非平凡构造函数的对象)。所以扩容唯一安全的做法是:分配新内存 → 逐个调用移动/拷贝构造 → 析构旧对象 → 释放旧内存。

常见错误是直接 memcpy 原始字节——对 int 没问题,但对 std::string 这类含指针、引用计数的对象会双释放或悬垂指针。

  • 正确做法:对每个旧元素调用 T(std::move(old[i])) 或 T(old[i]) 构造到新地址
  • 必须用 std::allocator_traits<t>::construct</t> 或手动调用构造函数,不能跳过
  • 旧元素析构前,必须确保新位置已构造完成,否则异常安全难保证

push_back 触发扩容时,如何避免重复计算容量?

每次 push_back 都检查 size_ == capacity_ 是必须的,但扩容倍数策略直接影响性能。用固定加法(如 +1)会导致 O(n²) 复杂度;用乘性增长(如 ×1.5 或 ×2)才能摊还为 O(1)。

注意:×2 简单但可能浪费内存;×1.5 更省空间但需浮点运算或整数技巧(如 new_cap = size_ + size_ / 2)。实际中 std::vector 通常用 ×2。

C++ Code Review Master
C++ Code Review Master

组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。

下载
  • 扩容前先算好 new_capacity,不要在循环里反复计算
  • 首次分配建议设为 1 或 2,避免空 vector 也 malloc 一次
  • 如果传入初始 n,直接分配 n 容量,别先分配 0 再 push n 次

怎么安全处理 T 是 move-only 类型(如 std::unique_ptr)?

手写 vector 必须区分 T 是否支持移动。若只用 copy,对 unique_ptr 编译不过;若盲目用 move,对 int 虽无害但冗余。标准做法是优先 move,fallback 到 copy。

核心是用 std::is_nothrow_move_constructible_v<t></t> 和 std::is_copy_constructible_v<t></t> 做 trait 判断,再配合 std::move 或 static_cast<const t></const>。

  • 构造新元素时:用 new (ptr) T(std::move(old_elem)),不是 new (ptr) T(old_elem)
  • 旧元素析构前,必须先完成所有新元素构造,否则异常发生时状态不一致
  • 别忘了在析构函数里对 [0, size_) 区间内每个元素显式调用 obj.~T()

为什么不能直接继承 std::allocator 来管理内存?

可以继承,但没必要,且容易误用。std::allocator 只负责 raw 内存分配/释放(allocate/deallocate),不负责对象构造/析构。真正要复用的是它的接口约定,而不是继承它。

更轻量、更可控的做法是封装一个 allocator_type 类型别名,默认用 std::allocator<t></t>,并在内部调用 alloc_.allocate(n) 和 alloc_.deallocate(ptr, n)。

  • 自己 new/delete 容易漏掉对齐要求(尤其 C++17 后 operator new 支持对齐参数)
  • 用 std::allocator 可无缝对接自定义 allocator(比如 arena allocator)
  • 别在类里硬编码 sizeof(T) —— 让 allocator 自己算
真实手写时最常被忽略的,是异常安全边界:只要新内存分配成功、但某个元素构造抛异常,就必须立即析构已构造的新元素,并释放新内存,然后重新抛出——这个 try-catch 块不能少,也不能只包构造不包析构。

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

c++ c++动态数组

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.02

5679

3

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.02

5679

3

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.08.29

2825

6

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

2025.08.29

3548

10

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

2025.08.29

2525

10

C++ 智能指针与现代内存管理
C++ 智能指针与现代内存管理

深入讲解 C++ 现代内存管理的核心工具——智能指针,涵盖 unique_ptr 独占所有权语义、shared_ptr 引用计数机制与循环引用问题、weak_ptr 弱引用的应用场景、make_unique/make_shared 工厂函数的性能优势、自定义删除器的编写、RAII 资源管理思想的实践,以及从裸指针迁移到智能指针的重构策略,帮助开发者编写安全无泄漏的现代 C++ 代码。

2026.04.23

319

31

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

2023.10.19

3088

3

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

2025.10.17

4529

12

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2025.12.29

3709

9

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Conan 2 Essentials 免费课程
Conan 2 Essentials 免费课程

共0课时 | 0人学习

CMake 与 Conan 集成实践
CMake 与 Conan 集成实践

共0课时 | 0人学习

Conan 2 高级依赖模型介绍
Conan 2 高级依赖模型介绍

共0课时 | 0人学习