《手搓一个STL风格vector容器》
# 手搓一个STL风格vector容器
## 前言
在C++标准库中,`vector`是最常用的动态数组容器之一。本文将从头开始实现一个简化版的STL风格`vector`容器,深入探讨其内部实现机制。通过这个实践项目,我们可以更好地理解:
1. 动态数组的内存管理原理
2. 模板编程在容器中的应用
3. 迭代器设计模式
4. 异常安全保证
5. STL容器的接口规范
---
## 一、基础框架搭建
### 1.1 类模板定义
我们首先定义`vector`的类模板框架:
```cpp
template <typename T>
class Vector {
public:
// 类型别名
using value_type = T;
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = const T&;
using size_type = size_t;
using difference_type = ptrdiff_t;
private:
pointer m_data; // 数据指针
size_type m_size; // 当前元素数量
size_type m_capacity; // 当前容量
public:
// 构造/析构函数
Vector() noexcept;
explicit Vector(size_type count);
Vector(size_type count, const T& value);
~Vector();
// 拷贝控制
Vector(const Vector& other);
Vector& operator=(const Vector& other);
// 容量相关
bool empty() const noexcept;
size_type size() const noexcept;
size_type capacity() const noexcept;
void reserve(size_type new_cap);
// 元素访问
reference operator[](size_type pos);
const_reference operator[](size_type pos) const;
reference at(size_type pos);
const_reference at(size_type pos) const;
// 修改操作
void push_back(const T& value);
void pop_back();
void clear() noexcept;
};
1.2 内存管理实现
// 默认构造函数
template <typename T>
Vector<T>::Vector() noexcept
: m_data(nullptr), m_size(0), m_capacity(0) {}
// 带初始大小的构造函数
template <typename T>
Vector<T>::Vector(size_type count) {
m_data = static_cast<pointer>(::operator new(count * sizeof(T)));
m_size = count;
m_capacity = count;
// 默认构造元素
for (size_type i = 0; i < count; ++i) {
new (m_data + i) T();
}
}
// 析构函数
template <typename T>
Vector<T>::~Vector() {
clear();
::operator delete(m_data);
}
二、核心功能实现
2.1 动态扩容机制
vector的核心特性是能够动态增长,这是通过reserve和push_back实现的:
template <typename T>
void Vector<T>::reserve(size_type new_cap) {
if (new_cap <= m_capacity) return;
// 分配新内存
pointer new_data = static_cast<pointer>(::operator new(new_cap * sizeof(T)));
// 移动构造现有元素
for (size_type i = 0; i < m_size; ++i) {
new (new_data + i) T(std::move(m_data[i]));
m_data[i].~T(); // 析构原对象
}
// 释放旧内存
::operator delete(m_data);
m_data = new_data;
m_capacity = new_cap;
}
template <typename T>
void Vector<T>::push_back(const T& value) {
if (m_size >= m_capacity) {
// 扩容策略:首次分配1,之后翻倍
reserve(m_capacity == 0 ? 1 : m_capacity * 2);
}
// 在末尾构造新元素
new (m_data + m_size) T(value);
++m_size;
}
2.2 元素访问实现
template <typename T>
typename Vector<T>::reference Vector<T>::operator[](size_type pos) {
return m_data[pos];
}
template <typename T>
typename Vector<T>::reference Vector<T>::at(size_type pos) {
if (pos >= m_size) {
throw std::out_of_range("Vector::at");
}
return m_data[pos];
}
三、迭代器实现
3.1 迭代器类定义
template <typename T>
class VectorIterator {
public:
using iterator_category = std::random_access_iterator_tag;
using value_type = T;
using difference_type = ptrdiff_t;
using pointer = T*;
using reference = T&;
explicit VectorIterator(pointer ptr) : m_ptr(ptr) {}
// 解引用
reference operator*() const { return *m_ptr; }
pointer operator->() const { return m_ptr; }
// 前缀++
VectorIterator& operator++() {
++m_ptr;
return *this;
}
// 后缀++
VectorIterator operator++(int) {
VectorIterator tmp = *this;
++m_ptr;
return tmp;
}
// 比较运算符
bool operator==(const VectorIterator& other) const {
return m_ptr == other.m_ptr;
}
// 其他必要操作...
private:
pointer m_ptr;
};
3.2 容器迭代器接口
template <typename T>
VectorIterator<T> Vector<T>::begin() {
return VectorIterator<T>(m_data);
}
template <typename T>
VectorIterator<T> Vector<T>::end() {
return VectorIterator<T>(m_data + m_size);
}
四、完整功能测试
4.1 基础功能测试
void test_vector_basic() {
Vector<int> vec;
// 测试push_back
for (int i = 0; i < 10; ++i) {
vec.push_back(i * i);
}
// 测试迭代器
std::cout << "Elements: ";
for (auto it = vec.begin(); it != vec.end(); ++it) {
std::cout << *it << " ";
}
std::cout << "\n";
// 测试随机访问
std::cout << "vec[5] = " << vec[5] << "\n";
// 测试异常
try {
std::cout << vec.at(20) << "\n";
} catch (const std::out_of_range& e) {
std::cerr << "Out of range: " << e.what() << "\n";
}
}
4.2 性能对比测试
void test_performance() {
const size_t N = 1000000;
// 测试我们的Vector
auto start1 = std::chrono::high_resolution_clock::now();
Vector<int> my_vec;
for (size_t i = 0; i < N; ++i) {
my_vec.push_back(i);
}
auto end1 = std::chrono::high_resolution_clock::now();
// 测试std::vector
auto start2 = std::chrono::high_resolution_clock::now();
std::vector<int> std_vec;
for (size_t i = 0; i < N; ++i) {
std_vec.push_back(i);
}
auto end2 = std::chrono::high_resolution_clock::now();
// 输出结果
auto my_time = std::chrono::duration_cast<std::chrono::milliseconds>(end1 - start1);
auto std_time = std::chrono::duration_cast<std::chrono::milliseconds>(end2 - start2);
std::cout << "Our Vector: " << my_time.count() << "ms\n";
std::cout << "std::vector: " << std_time.count() << "ms\n";
}
五、优化与改进方向
5.1 当前实现的不足
- 缺少移动语义支持(C++11)
- 没有实现
emplace_back - 异常安全性可以进一步优化
- 缺少allocator支持
- 迭代器功能不完整
5.2 改进建议
- 实现移动构造函数和移动赋值运算符
- 添加
emplace_back支持原位构造 - 实现强异常安全保证
- 添加自定义allocator支持
- 完善迭代器的随机访问能力
- 实现
swap操作
结语
通过实现这个简化版的vector容器,我们深入理解了:
- 动态数组的内存管理策略
- 模板编程的实际应用
- 迭代器设计模式
- 异常安全的重要性
- STL容器的接口规范
虽然我们的实现与标准库的vector相比还有差距,但已经包含了核心功能。建议读者可以在此基础上继续完善,这将是对C++模板和内存管理能力的极好锻炼。