《手搓一个STL风格vector容器》

52 阅读4分钟

《手搓一个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的核心特性是能够动态增长,这是通过reservepush_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 当前实现的不足

  1. 缺少移动语义支持(C++11)
  2. 没有实现emplace_back
  3. 异常安全性可以进一步优化
  4. 缺少allocator支持
  5. 迭代器功能不完整

5.2 改进建议

  1. 实现移动构造函数和移动赋值运算符
  2. 添加emplace_back支持原位构造
  3. 实现强异常安全保证
  4. 添加自定义allocator支持
  5. 完善迭代器的随机访问能力
  6. 实现swap操作

结语

通过实现这个简化版的vector容器,我们深入理解了:

  1. 动态数组的内存管理策略
  2. 模板编程的实际应用
  3. 迭代器设计模式
  4. 异常安全的重要性
  5. STL容器的接口规范

虽然我们的实现与标准库的vector相比还有差距,但已经包含了核心功能。建议读者可以在此基础上继续完善,这将是对C++模板和内存管理能力的极好锻炼。