vector 三个经典版本
·
vector 是动态连续数组,底层基于原生指针实现,是 STL 中最常用的序列式容器,核心特性:
- 内存连续分配,支持随机访问([]/at 访问效率 O (1));
- 迭代器本质是原生指针(T*),指针天然满足 STL 迭代器的所有要求;
- 核心成员是三个原生指针,所有操作都围绕这三个指针展开,这是 vector 源码的核心骨架;
- 存在容量 (capacity) 和大小 (size) 分离的设计,当插入元素导致
size == capacity时触发扩容,扩容是 vector 性能损耗的核心点; - SGI STL(工业界主流实现,gcc/libstdc++ 采用)的核心设计思想:内存分配 和 对象构造分离、内存释放 和 对象析构分离,这是所有 STL 容器的通用内存管理范式。
三个版本
- 版本一:原生朴素版(三指针裸版) - 无任何优化,纯基础实现,vector 的本源,也是你之前看过的核心版本;
- 版本二:写时拷贝版(COW 版,Copy-On-Write) - 基于版本一的性能优化,引用计数 + 共享内存,90 年代~gcc5.0 的主流版本;
- 版本三:小对象优化版(SBO 版,Small Buffer Optimization) - 工业级终极版本,当前 gcc/clang/msvc 默认实现,无任何致命缺陷,兼顾极致性能 + 安全性,生产环境唯一使用版本。
版本一:原生朴素版(三指针裸版 / 基础版)
核心特征
- 底层纯 3 个原生指针,无任何额外成员变量,vector 的最基础形态;
- 严格深拷贝:拷贝构造 / 赋值运算符都会完整拷贝堆内存的所有元素,新对象独占内存;
- 无任何优化,逻辑极简,无坑点,是理解 vector 的基石;
- 所有操作都是「直来直去」,迭代器失效规则最简单。
完整可编译源码
#include <memory>
#include <algorithm>
#include <stdexcept>
template <typename T, typename Alloc = std::allocator<T>>
class vector_v1 { // v1: 原生朴素版
public:
// STL标准类型别名
using value_type = T;
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = const T&;
using iterator = T*;
using const_iterator = const T*;
using size_type = size_t;
using difference_type = ptrdiff_t;
protected:
// ========== 核心成员:纯三指针,无任何多余变量 ==========
iterator start; // 指向内存中第一个有效元素
iterator finish; // 指向内存中最后一个有效元素的下一位
iterator end_of_storage;//指向内存容量的最后一个位置的下一位
using data_allocator = typename Alloc::template rebind<T>::other;
// 内存工具:分配/释放/构造/析构 分离
pointer allocate(size_type n) { return n ? data_allocator::allocate(n) : nullptr; }
void deallocate(pointer p, size_type n) { if (p) data_allocator::deallocate(p, n); }
void construct(pointer p, const T& val) { data_allocator::construct(p, val); }
void destroy(pointer p) { data_allocator::destroy(p); }
void destroy(iterator first, iterator last) { for (; first != last; ++first) destroy(first); }
public:
// 构造函数
vector_v1() noexcept : start(nullptr), finish(nullptr), end_of_storage(nullptr) {}
explicit vector_v1(size_type n, const T& val = T{}) {
start = allocate(n);
end_of_storage = start + n;
finish = std::uninitialized_fill_n(start, n, val);
}
template <typename InputIter>
vector_v1(InputIter first, InputIter last) {
size_type n = std::distance(first, last);
start = allocate(n);
end_of_storage = start + n;
finish = std::uninitialized_copy(first, last, start);
}
// 深拷贝构造
vector_v1(const vector_v1& rhs) {
start = allocate(rhs.capacity());
end_of_storage = start + rhs.capacity();
finish = std::uninitialized_copy(rhs.start, rhs.finish, start);
}
// 深拷贝赋值
vector_v1& operator=(const vector_v1& rhs) {
if (this != &rhs) {
destroy(start, finish);
deallocate(start, capacity());
start = allocate(rhs.capacity());
end_of_storage = start + rhs.capacity();
finish = std::uninitialized_copy(rhs.start, rhs.finish, start);
}
return *this;
}
// 析构函数
~vector_v1() { destroy(start, finish); deallocate(start, capacity()); }
// 迭代器
iterator begin() noexcept { return start; }
const_iterator begin() const noexcept { return start; }
iterator end() noexcept { return finish; }
const_iterator end() const noexcept { return finish; }
// 容量/大小
size_type size() const noexcept { return finish - start; }
size_type capacity() const noexcept { return end_of_storage - start; }
bool empty() const noexcept { return start == finish; }
// 扩容:仅扩容容量,不改变元素个数
void reserve(size_type n) {
if (n > capacity()) {
size_type old_size = size();
pointer tmp = allocate(n);
finish = std::uninitialized_move(start, finish, tmp);
destroy(start, finish);
deallocate(start, capacity());
start = tmp;
end_of_storage = tmp + n;
}
}
// 元素访问
reference operator[](size_type n) noexcept { return start[n]; }
const_reference operator[](size_type n) const noexcept { return start[n]; }
reference at(size_type n) {
if (n >= size()) throw std::out_of_range("vector_v1::at out of range");
return start[n];
}
reference front() noexcept { return *start; }
const_reference front() const noexcept { return *start; }
reference back() noexcept { return *(finish - 1); }
const_reference back() const noexcept { return *(finish - 1); }
// 核心操作
void push_back(const T& val) {
if (finish == end_of_storage) reserve(capacity() ? 2 * capacity() : 1);
construct(finish++, val);
}
void pop_back() noexcept { if (!empty()) destroy(--finish); }
iterator erase(iterator pos) noexcept {
if (pos + 1 != end()) std::copy(pos+1, finish, pos);
destroy(--finish);
return pos;
}
void clear() noexcept { destroy(start, finish); finish = start; }
};
版本二:写时拷贝版(COW 版 / 引用计数版,Copy-On-Write)
核心特征
- 基于版本一的三指针模型改造,核心优化:共享内存 + 引用计数;
- 核心思想:读共享、写拷贝,拷贝构造 / 赋值运算符是「浅拷贝」,只拷贝指针,引用计数 + 1,时间复杂度 O (1),解决版本一深拷贝的性能痛点;
- 引用计数存储在堆内存的最起始位置(所有共享对象共用同一个引用计数);
- 所有写操作(push_back/pop_back/erase/operator [] 修改)前必须做
unshare()检查:如果引用计数 > 1,说明有其他对象共享内存,此时触发「深拷贝」,独占内存后再写;读操作无拷贝; - 析构逻辑:引用计数 - 1,只有计数减到 0 时,才真正释放堆内存;
- ✘ 致命缺陷:线程不安全、写操作有隐性延迟拷贝开销、迭代器失效规则复杂 → C++11 废弃,gcc5.0 后彻底移除。
完整可编译源码
#include <memory>
#include <algorithm>
#include <stdexcept>
#include <atomic>
template <typename T, typename Alloc = std::allocator<T>>
class vector_v2 { // v2: 写时拷贝版 COW (Copy-On-Write)
public:
using value_type = T;
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = const T&;
using iterator = T*;
using const_iterator = const T*;
using size_type = size_t;
using difference_type = ptrdiff_t;
protected:
// ========== COW核心改造:堆内存首地址存【引用计数】,后接数据区 ==========
// 内存布局:[ refcount (引用计数) | start -> 数据区 | finish | end_of_storage ]
iterator start;
iterator finish;
iterator end_of_storage;
using data_allocator = typename Alloc::template rebind<T>::other;
using refcount_alloc = typename Alloc::template rebind<size_type>::other;
// 【核心】获取引用计数的指针(堆内存首地址)
size_type* get_refcount() const noexcept { return reinterpret_cast<size_type*>(start) - 1; }
// 分配内存:先分配1个引用计数的空间,再分配n个元素的空间
pointer allocate_with_ref(size_type n) {
if (n == 0) return nullptr;
size_type* ref = refcount_alloc::allocate(1);
*ref = 1; // 初始引用计数=1
return reinterpret_cast<pointer>(ref + 1); // 跳过引用计数,返回数据区首地址
}
// 释放内存:先释放引用计数,再释放数据区
void deallocate_with_ref(pointer p, size_type n) {
if (p) {
size_type* ref = get_refcount();
refcount_alloc::deallocate(ref, 1);
data_allocator::deallocate(p, n);
}
}
void construct(pointer p, const T& val) { data_allocator::construct(p, val); }
void destroy(pointer p) { data_allocator::destroy(p); }
void destroy(iterator first, iterator last) { for (; first != last; ++first) destroy(first); }
// ========== COW核心函数:unshare 写时分离 ==========
// 写操作前必须调用,确保当前对象独占内存
void unshare(size_type need = 0) {
size_type* ref = get_refcount();
// 引用计数>1 → 有其他对象共享,需要深拷贝独占内存
if (*ref > 1) {
size_type old_size = size();
size_type new_cap = std::max(need, capacity());
pointer new_start = allocate_with_ref(new_cap);
std::uninitialized_move(start, finish, new_start);
// 原内存的引用计数-1,若为0则释放
if (--(*ref) == 0) deallocate_with_ref(start, capacity());
// 更新指针,指向新的独占内存
start = new_start;
finish = new_start + old_size;
end_of_storage = new_start + new_cap;
}
}
public:
// 构造函数
vector_v2() noexcept : start(nullptr), finish(nullptr), end_of_storage(nullptr) {}
explicit vector_v2(size_type n, const T& val = T{}) {
start = allocate_with_ref(n);
end_of_storage = start + n;
finish = std::uninitialized_fill_n(start, n, val);
}
template <typename InputIter>
vector_v2(InputIter first, InputIter last) {
size_type n = std::distance(first, last);
start = allocate_with_ref(n);
end_of_storage = start + n;
finish = std::uninitialized_copy(first, last, start);
}
// 【核心】COW拷贝构造:浅拷贝指针,引用计数+1 → O(1)时间
vector_v2(const vector_v2& rhs) noexcept {
if (rhs.empty()) { start = finish = end_of_storage = nullptr; return; }
start = rhs.start;
finish = rhs.finish;
end_of_storage = rhs.end_of_storage;
++(*get_refcount()); // 引用计数+1
}
// 【核心】COW赋值运算符:浅拷贝指针,引用计数+1 → O(1)时间
vector_v2& operator=(const vector_v2& rhs) noexcept {
if (this != &rhs) {
// 释放当前对象的引用
if (!empty() && --(*get_refcount()) == 0) deallocate_with_ref(start, capacity());
// 浅拷贝
start = rhs.start;
finish = rhs.finish;
end_of_storage = rhs.end_of_storage;
if (!empty()) ++(*get_refcount());
}
return *this;
}
// 析构函数:引用计数-1,只有0时才释放内存
~vector_v2() {
if (!empty() && --(*get_refcount()) == 0) deallocate_with_ref(start, capacity());
}
// 迭代器:const迭代器只读,无需unshare;非const迭代器可能写,需unshare
const_iterator begin() const noexcept { return start; }
const_iterator end() const noexcept { return finish; }
iterator begin() noexcept { unshare(); return start; }
iterator end() noexcept { unshare(); return finish; }
// 容量/大小:只读操作,无需unshare
size_type size() const noexcept { return finish - start; }
size_type capacity() const noexcept { return end_of_storage - start; }
bool empty() const noexcept { return start == finish; }
// 元素访问:const是读操作,无拷贝;非const是写操作,必须unshare
const_reference operator[](size_type n) const noexcept { return start[n]; }
reference operator[](size_type n) noexcept { unshare(); return start[n]; }
const_reference front() const noexcept { return *start; }
reference front() noexcept { unshare(); return *start; }
const_reference back() const noexcept { return *(finish - 1); }
reference back() noexcept { unshare(); return *(finish - 1); }
// ========== 所有写操作:必须先unshare ==========
void push_back(const T& val) {
if (empty()) reserve(1);
if (finish == end_of_storage) unshare(2 * capacity());
construct(finish++, val);
}
void pop_back() noexcept {
if (!empty()) { unshare(); destroy(--finish); }
}
iterator erase(iterator pos) noexcept {
if (empty() || pos >= finish) return finish;
unshare();
if (pos + 1 != end()) std::copy(pos+1, finish, pos);
destroy(--finish);
return pos;
}
void clear() noexcept {
if (!empty()) { unshare(); destroy(start, finish); finish = start; }
}
void reserve(size_type n) {
if (n > capacity()) unshare(n);
}
};
版本三:小对象优化版(SBO 版,Small Buffer Optimization)
核心特征
- 当前所有编译器(gcc/clang/msvc)的默认实现,生产环境唯一使用版本,无任何致命缺陷;
- 核心优化:栈上内置缓冲区 + 堆内存动态切换,完美解决版本一的「小对象堆分配开销」和版本二的「线程安全坑」;
- 内存布局:用联合体 (union) 做内存复用(栈 / 堆模式互斥),无内存浪费,极致紧凑;
- 核心原则:小数据走栈、大数据走堆:当元素个数 ≤ 内置缓冲区大小(工业级标准
16),直接存在对象自身的栈内存中,无 malloc/free 开销,极致快;超过则自动切换为版本一的堆内存模式,完全兼容; - 回归值语义 + 深拷贝,无引用计数,天然线程安全,迭代器失效规则和版本一一致,逻辑简单;
- 对外接口和版本一完全一致,调用无感知,性能碾压版本一 / 二,是 vector 的最优解。
补充:string 的该版本叫 SSO (Small String Optimization),本质和 SBO 是同一个东西,只是命名不同。
完整可编译源码
#include <memory>
#include <algorithm>
#include <stdexcept>
#include <cstring>
template <typename T, typename Alloc = std::allocator<T>, size_type SBO_SIZE = 16>
class vector_v3 { // v3: 小对象优化版 SBO (Small Buffer Optimization) 【工业级终极版】
public:
using value_type = T;
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = const T&;
using iterator = T*;
using const_iterator = const T*;
using size_type = size_t;
using difference_type = ptrdiff_t;
static constexpr size_type SBO_BUFFER_SIZE = SBO_SIZE; // 工业级标准:16个元素
protected:
// ========== SBO核心:联合体 内存复用(栈/堆模式互斥) ==========
// 状态标记:栈模式(small) / 堆模式(large)
enum class Mode { Small, Large };
Mode mode;
// 堆模式:复用版本一的三指针
struct HeapData {
iterator start;
iterator finish;
iterator end_of_storage;
};
// 栈模式:内置缓冲区,栈内存存储,无堆分配
struct StackData {
T buf[SBO_BUFFER_SIZE]; // 栈上缓冲区,存小对象
size_type size_; // 栈模式下的元素个数
};
// 联合体:栈/堆模式二选一,内存复用,无浪费
union Data {
HeapData heap;
StackData stack;
Data() {}
~Data() {} // 联合体析构手动控制
} data;
using data_allocator = typename Alloc::template rebind<T>::other;
// 内存工具:分配/释放/构造/析构 分离
pointer allocate(size_type n) { return n ? data_allocator::allocate(n) : nullptr; }
void deallocate(pointer p, size_type n) { if (p) data_allocator::deallocate(p, n); }
void construct(pointer p, const T& val) { data_allocator::construct(p, val); }
void destroy(pointer p) { data_allocator::destroy(p); }
void destroy(iterator first, iterator last) { for (; first != last; ++first) destroy(first); }
// 核心:判断当前模式
bool is_small() const noexcept { return mode == Mode::Small; }
bool is_large() const noexcept { return mode == Mode::Large; }
// 统一的指针访问接口:对上层透明,不用关心栈/堆
iterator get_start() noexcept {
return is_small() ? data.stack.buf : data.heap.start;
}
iterator get_finish() noexcept {
return is_small() ? data.stack.buf + data.stack.size_ : data.heap.finish;
}
iterator get_end_storage() noexcept {
return is_small() ? data.stack.buf + SBO_BUFFER_SIZE : data.heap.end_of_storage;
}
const_iterator get_start() const noexcept {
return is_small() ? data.stack.buf : data.heap.start;
}
const_iterator get_finish() const noexcept {
return is_small() ? data.stack.buf + data.stack.size_ : data.heap.finish;
}
const_iterator get_end_storage() const noexcept {
return is_small() ? data.stack.buf + SBO_BUFFER_SIZE : data.heap.end_of_storage;
}
// 扩容核心:栈→堆 切换 / 堆扩容
void reallocate(size_type new_cap) {
size_type old_size = size();
T* old_start = get_start();
// 分配新内存(堆)
T* new_start = allocate(new_cap);
T* new_finish = std::uninitialized_move(old_start, old_start + old_size, new_start);
// 清理旧内存
if (is_large()) {
destroy(data.heap.start, data.heap.finish);
deallocate(data.heap.start, data.heap.end_of_storage - data.heap.start);
} else {
destroy(data.stack.buf, data.stack.buf + old_size);
}
// 切换为堆模式,更新指针
mode = Mode::Large;
data.heap.start = new_start;
data.heap.finish = new_finish;
data.heap.end_of_storage = new_start + new_cap;
}
public:
// 构造函数:默认初始化为栈模式,空容器
vector_v3() noexcept : mode(Mode::Small) { data.stack.size_ = 0; }
explicit vector_v3(size_type n, const T& val = T{}) : mode(Mode::Small) {
if (n <= SBO_BUFFER_SIZE) { // 小对象:栈模式
data.stack.size_ = n;
std::uninitialized_fill_n(data.stack.buf, n, val);
} else { // 大对象:堆模式
reallocate(n);
std::uninitialized_fill_n(data.heap.start, n, val);
data.heap.finish = data.heap.start + n;
}
}
template <typename InputIter>
vector_v3(InputIter first, InputIter last) : mode(Mode::Small) {
size_type n = std::distance(first, last);
if (n <= SBO_BUFFER_SIZE) {
data.stack.size_ = n;
std::uninitialized_copy(first, last, data.stack.buf);
} else {
reallocate(n);
std::uninitialized_copy(first, last, data.heap.start);
data.heap.finish = data.heap.start + n;
}
}
// 深拷贝构造:栈/堆模式都完整拷贝,值语义
vector_v3(const vector_v3& rhs) : mode(rhs.mode) {
if (rhs.is_small()) {
data.stack.size_ = rhs.data.stack.size_;
std::uninitialized_copy(rhs.data.stack.buf, rhs.data.stack.buf + rhs.size(), data.stack.buf);
} else {
data.heap.start = allocate(rhs.capacity());
data.heap.end_of_storage = data.heap.start + rhs.capacity();
data.heap.finish = std::uninitialized_copy(rhs.data.heap.start, rhs.data.heap.finish, data.heap.start);
}
}
// 深拷贝赋值
vector_v3& operator=(const vector_v3& rhs) {
if (this != &rhs) {
clear();
if (rhs.is_small()) {
mode = Mode::Small;
data.stack.size_ = rhs.size();
std::uninitialized_copy(rhs.data.stack.buf, rhs.data.stack.buf + rhs.size(), data.stack.buf);
} else {
reallocate(rhs.capacity());
std::uninitialized_copy(rhs.data.heap.start, rhs.data.heap.finish, data.heap.start);
data.heap.finish = data.heap.start + rhs.size();
}
}
return *this;
}
// 析构函数:手动控制栈/堆的析构逻辑
~vector_v3() { clear(); }
// 迭代器:统一接口,透明访问
iterator begin() noexcept { return get_start(); }
const_iterator begin() const noexcept { return get_start(); }
iterator end() noexcept { return get_finish(); }
const_iterator end() const noexcept { return get_finish(); }
// 容量/大小:统一计算,无感知
size_type size() const noexcept { return get_finish() - get_start(); }
size_type capacity() const noexcept { return get_end_storage() - get_start(); }
bool empty() const noexcept { return size() == 0; }
// 元素访问:统一接口,极致性能
reference operator[](size_type n) noexcept { return get_start()[n]; }
const_reference operator[](size_type n) const noexcept { return get_start()[n]; }
reference front() noexcept { return *get_start(); }
const_reference front() const noexcept { return *get_start(); }
reference back() noexcept { return *(get_finish() - 1); }
const_reference back() const noexcept { return *(get_finish() - 1); }
// 核心操作:栈/堆自动切换,性能拉满
void push_back(const T& val) {
if (size() >= capacity()) reallocate(capacity() ? 2 * capacity() : 1);
construct(get_finish(), val);
if (is_small()) data.stack.size_++;
else data.heap.finish++;
}
void pop_back() noexcept {
if (!empty()) {
if (is_small()) destroy(data.stack.buf + --data.stack.size_);
else destroy(--data.heap.finish);
}
}
iterator erase(iterator pos) noexcept {
if (empty() || pos >= end()) return end();
if (pos + 1 != end()) std::copy(pos+1, end(), pos);
pop_back();
return pos;
}
void clear() noexcept {
if (is_small()) {
destroy(data.stack.buf, data.stack.buf + data.stack.size_);
data.stack.size_ = 0;
} else {
destroy(data.heap.start, data.heap.finish);
deallocate(data.heap.start, data.heap.end_of_storage - data.heap.start);
mode = Mode::Small;
data.stack.size_ = 0;
}
}
void reserve(size_type n) { if (n > capacity()) reallocate(n); }
};
- vector 的三个版本演进,本质是 「性能与安全性的权衡」:版本一追求安全但性能差,版本二追求性能但牺牲安全,版本三兼顾性能与安全,是终极解;
- string 和 vector 完全同源,三个版本的实现逻辑、演进过程、优缺点完全一致,只是 string 的 SBO 叫 SSO,缓冲区存 char;
- 三个版本的对外接口完全一致,替换使用时无需修改任何调用代码,这是 STL 的封装精髓。
更多推荐



所有评论(0)