vector`的底层实现

在C++标准库中,vector的底层实现是一个动态数组,其核心原理和关键特性如下:


一、底层数据结构

  1. 连续内存空间
    • 使用连续内存块存储元素,支持O(1)时间的随机访问(通过下标或指针算术)。
    • 内部通过三个指针管理内存:
      • _Myfirst:指向数组的首元素。
      • _Mylast:指向最后一个有效元素的下一个位置(等价于size())。
      • _Myend:指向已分配内存的末尾(等价于capacity())。
  2. 动态扩容机制
    • 当插入元素导致size() == capacity()时,触发扩容:
      • 分配新内存(通常为旧容量的 2倍1.5倍,具体由编译器实现决定)。vs 一般是1.5倍 gcc 2倍。
      • 将旧元素移动或拷贝到新内存(C++11后优先使用移动语义)。
      • 释放旧内存。
    • 扩容使操作均摊时间复杂度为 O(1)(例如,插入n个元素的总时间为O(n))。
    • 2倍扩容为什么不好?空间浪费。扩容时无法复用已经释放的内存。优点:扩容次数相对较少。
    • 扩容是采用malloc还是new? 分配器对内存分配和构造进行分离。使用malloc 分配内存,使用placement new 构造对象。
    • 怎么避免扩容带来的移动代价? 在能预测元素的个数的情况下,预分配空间。

二、关键操作复杂度

操作时间复杂度说明
随机访问([], atO(1)直接通过内存偏移访问。
尾部插入/删除O(1) 均摊可能触发扩容/缩容。
头部或中间插入/删除O(n)需要移动后续元素。

三、迭代器失效场景

1.  扩容引起迭代器失效,

2. 元素移动导致迭代器失效

3. `reserve()`**/**`shrink_to_fit()`:可能改变内存地址,导致迭代器失效。

四、性能优化技巧

  1. 预分配内存
    使用reserve()提前分配足够容量,避免多次扩容:
std::vector<int> vec;
vec.reserve(100);  // 预分配100个元素的容量
  1. 减少中间插入
    频繁在头部或中间插入时,考虑改用std::dequestd::list
  2. 利用移动语义
    对于占用资源较多的对象(如std::string),使用std::move避免拷贝:
std::vector<std::string> vec;
std::string s = "data";
vec.push_back(std::move(s));  // 移动而非拷贝

emplace_back 相对 push_back 有性能提升。主要因为就地构造


五、与其他容器的对比

特性vectorstd::liststd::deque
内存布局连续内存双向链表分块连续内存
随机访问O(1)O(n)O(1)
尾部插入/删除高效高效高效
中间插入/删除低效高效低效
迭代器失效易失效局部失效局部失效

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值