【C++】 vector(代码实现+坑点讲解)

作为C++标准模板库(STL)中最基础、最常用的容器之一,vector提供了动态数组的功能。今天我们将深入探讨如何从零实现一个完整的vector容器,理解其内部工作原理和设计思想。


代码解释:C++ Vector模板类实现

代码整体功能和主要作用

C++动态数组(vector)模板类实现,其主要功能包括:

  1. 动态数组管理:自动扩容的动态数组容器

  2. 类型安全:通过模板支持任意类型

  3. 内存管理:自动内存分配和释放

  4. 迭代器支持:提供随机访问迭代器

  5. STL风格接口:与标准库vector类似的接口

一. 主要功能模块分析

1.1 核心设计思想

我们的vector实现基于以下核心思想:

  1. 动态连续内存:元素在内存中连续存储,支持随机访问

  2. 三指针模型:通过三个指针管理内存区间

  3. 指数扩容策略:避免频繁内存分配

  4. RAII原则:构造函数分配,析构函数释放

1.2 类定义框架

复制代码
#pragma once
#include<assert.h>
#include <initializer_list> 

namespace wxx
{
    template<class T>
    class vector
    {
    public:
        // 类型定义
        typedef T* iterator;
        typedef const T* const_iterator;
        
    private:
        // 三指针模型
        iterator _start = nullptr;        // 起始位置
        iterator _finish = nullptr;       // 有效元素末尾的下一个位置
        iterator _endofstorage = nullptr; // 分配内存的末尾
        
        // ... 成员函数实现
    };
}

二、迭代器设计与实现

在C++中,迭代器是抽象化的指针。对于vector,由于内存连续,我们可以直接用原生指针作为迭代器:

复制代码
typedef T* iterator;
typedef const T* const_iterator;

iterator begin() { return _start; }
iterator end() { return _finish; }
const_iterator begin() const { return _start; }
const_iterator end() const { return _finish; }

三、构造函数家族

3.1 多种构造方式

复制代码
// 默认构造
vector() = default;

// 初始化列表构造(C++11特性)
vector(std::initializer_list<T> il)
{
    reserve(il.size());
    for (auto& e : il)
    {
        push_back(e);
    }
}

// 拷贝构造
vector(const vector<T>& v)
{
    reserve(v.capacity());  // 预分配足够空间
    for (auto& e : v)
    {
        push_back(e);  // 深拷贝每个元素
    }
}

// 迭代器范围构造
template<class InputIterator,
    typename std::enable_if<!std::is_integral<InputIterator>::value, int>::type = 0>
vector(InputIterator first, InputIterator last)
{
    while (first != last)
    {
        push_back(*first);
        ++first;
    }
}

// 指定数量和值的构造
vector(size_t n, T val = T())
{
    resize(n, val);
}

3.2 SFINAE技术应用

注意迭代器范围构造函数中的特殊语法:

复制代码
template<class InputIterator,
    typename std::enable_if<!std::is_integral<InputIterator>::value, int>::type = 0>

这是SFINAE(Substitution Failure Is Not An Error)技术的应用。其作用是:

  1. InputIterator是整数类型时,模板替换失败

  2. 编译器会选择vector(size_t n, T val)构造函数

  3. 避免了构造函数的歧义调用

四、内存管理与扩容策略

4.1 reserve函数实现

复制代码
void reserve(size_t n)
{
    if (n > capacity())
    {
        size_t old_size = size();
        T* tmp = new T[n];  // 1. 分配新内存
        
        if (_start)  // 2. 拷贝旧数据
        {
            for (size_t i = 0; i < old_size; i++)
            {
                tmp[i] = _start[i];  // 调用T的拷贝赋值运算符
            }
            delete[] _start;  // 3. 释放旧内存
        }
        
        // 4. 更新指针
        _start = tmp;
        _finish = _start + old_size;
        _endofstorage = _start + n;
    }
}

关键点:

  1. 先分配,再拷贝,最后释放,保证异常安全

  2. 使用循环而不是memcpy,确保调用正确的拷贝赋值运算符

  3. 正确处理从无到有的情况

4.2 push_back与扩容策略

复制代码
void push_back(const T& x)
{
    if (_finish == _endofstorage)  // 需要扩容
    {
        // 指数增长策略
        reserve(capacity() == 0 ? 4 : capacity() * 2);
    }
    *_finish = x;  // 在末尾构造元素
    ++_finish;     // 更新大小
}

五、元素操作实现

5.1 insert操作详解

复制代码
iterator insert(iterator pos, const T& x)
{
    // 1. 检查位置有效性
    assert(pos >= _start);
    assert(pos <= _finish);
    
    // 2. 检查是否需要扩容
    if (_finish == _endofstorage)
    {
        // 记录偏移量,扩容后迭代器会失效
        size_t len = pos - _start;
        reserve(capacity() == 0 ? 4 : capacity() * 2);
        pos = _start + len;  // 重新计算位置
    }
    
    // 3. 向后移动元素
    iterator end = _finish - 1;
    while (end >= pos)
    {
        *(end + 1) = *end;  // 向后移动一位
        --end;
    }
    
    // 4. 插入新元素
    *pos = x;
    ++_finish;
    
    return pos;  // 返回新插入元素的位置
}

迭代器失效问题:

  • 扩容会导致所有迭代器失效

  • 需要重新计算插入位置

  • 返回新的迭代器,让调用者可以继续使用

5.2 erase操作实现

复制代码
iterator erase(iterator pos)
{
    assert(pos >= _start);
    assert(pos < _finish);

    // 向前移动元素,覆盖要删除的元素
    iterator it = pos + 1;
    while (it != _finish)
    {
        *(it - 1) = *it;
        ++it;
    }

    --_finish;  // 减少大小
    
    return pos;  // 返回被删除元素的位置
}

六、拷贝控制与异常安全

6.1 拷贝并交换技术

复制代码
// 拷贝赋值运算符
vector<T>& operator=(vector<T> v)  // 注意:传值参数
{
    swap(v);  // 交换当前对象和临时对象
    return *this;
    // v离开作用域,自动调用析构函数释放原资源
}

6.2 swap函数实现

复制代码
void swap(vector<T>& v)
{
    std::swap(_start, v._start);
    std::swap(_finish, v._finish);
    std::swap(_endofstorage, v._endofstorage);
}

特点:

  • O(1)时间复杂度

  • 不抛出异常(假设std::swap不抛异常)

  • 交换的是指针,不是实际数据

七、完整代码实现

以下是完整的vector实现代码:

复制代码
#pragma once
#include<assert.h>
#include <initializer_list> 
#include <type_traits>  // 需要包含这个头文件

namespace wxx
{
    template<class T>
    class vector
    {
    public:
        // 类型定义
        typedef T* iterator;
        typedef const T* const_iterator;
        
        // 迭代器
        iterator begin() { return _start; }
        iterator end() { return _finish; }
        const_iterator begin() const { return _start; }
        const_iterator end() const { return _finish; }
        
        // 构造函数
        vector() = default;
        
        // 初始化列表构造函数
        vector(std::initializer_list<T> il)
        {
            reserve(il.size());
            for (auto& e : il)
            {
                push_back(e);
            }
        }
        
        // 拷贝构造函数
        vector(const vector<T>& v)
        {
            reserve(v.capacity());
            for (auto& e : v)
            {
                push_back(e);
            }
        }
        
        // 交换函数
        void swap(vector<T>& v)
        {
            std::swap(_start, v._start);
            std::swap(_finish, v._finish);
            std::swap(_endofstorage, v._endofstorage);
        }
        
        // 赋值运算符(拷贝并交换)
        vector<T>& operator=(vector<T> v)
        {
            swap(v);
            return *this;
        }
        
        // 迭代器范围构造函数(使用SFINAE)
        template<class InputIterator,
            typename std::enable_if<!std::is_integral<InputIterator>::value, int>::type = 0>
        vector(InputIterator first, InputIterator last)
        {
            while (first != last)
            {
                push_back(*first);
                ++first;
            }
        }
        
        // 指定数量和值的构造函数
        vector(size_t n, T val = T())
        {
            resize(n, val);
        }
        
        // 析构函数
        ~vector()
        {
            if (_start)
            {
                delete[] _start;
                _start = _finish = _endofstorage = nullptr;
            }
        }
        
        // 容量管理
        void reserve(size_t n)
        {
            if (n > capacity())
            {
                size_t old_size = size();
                T* tmp = new T[n];
                if (_start)
                {
                    for (size_t i = 0; i < old_size; i++)
                    {
                        tmp[i] = _start[i];
                    }
                    delete[] _start;
                }
                _start = tmp;
                _finish = _start + old_size;
                _endofstorage = _start + n;
            }
        }
        
        void resize(size_t n, T val = T())
        {
            if (n > size())
            {
                reserve(n);
                while (_finish != _start + n)
                {
                    *_finish = val;
                    ++_finish;
                }
            }
            else 
            {
                _finish = _start + n;
            }
        }
        
        // 元素访问
        T& operator[](size_t i)
        {
            assert(i < size());
            return _start[i];
        }
        
        const T& operator[](size_t i) const
        {
            assert(i < size());
            return _start[i];
        }
        
        // 容量查询
        void clear() { _finish = _start; }
        size_t size() const { return _finish - _start; }
        size_t capacity() const { return _endofstorage - _start; }
        bool empty() const { return _start == _finish; }
        
        // 元素操作
        void push_back(const T& x)
        {
            if (_finish == _endofstorage)
            {
                reserve(capacity() == 0 ? 4 : capacity() * 2);
            }
            *_finish = x;
            ++_finish;
        }
        
        void pop_back()
        {
            assert(!empty());
            --_finish;
        }
        
        iterator insert(iterator pos, const T& x)
        {
            assert(pos >= _start);
            assert(pos <= _finish);
            if (_finish == _endofstorage)
            {
                size_t len = pos - _start;
                reserve(capacity() == 0 ? 4 : capacity() * 2);
                pos = _start + len;
            }
            iterator end = _finish - 1;
            while (end >= pos)
            {
                *(end + 1) = *end;
                --end;
            }
            *pos = x;
            ++_finish;
            return pos;
        }
        
        iterator erase(iterator pos)
        {
            assert(pos >= _start);
            assert(pos < _finish);

            iterator it = pos + 1;
            while (it != _finish)
            {
                *(it - 1) = *it;
                ++it;
            }

            --_finish;
            return pos;
        }
        
    private:
        iterator _start = nullptr;
        iterator _finish = nullptr;
        iterator _endofstorage = nullptr;
    };
    
} // namespace wxx

八、测试示例

源码分享

vector模拟实现 · 9f00357 · 加油少年/CCCCC - Gitee.comhttps://gitee.com/wxx547803_0/ccccc/commit/9f003570389e26bca34c5e62f3ba31da2005c3a1


相关推荐
野生技术架构师1 小时前
2026年最全Java面试题及答案汇总(建议收藏,面试前看这篇就够了)
java·开发语言·面试
百锦再2 小时前
Auto.js变成基础知识学习
开发语言·javascript·学习·sqlite·kotlin·android studio·数据库开发
叼烟扛炮2 小时前
C++第三讲:类和对象(中)
开发语言·c++·类和对象
KuaCpp2 小时前
C++新特性学习
c++·学习
墨染千千秋2 小时前
C/C++ Keywords
c语言·c++
ximu_polaris2 小时前
设计模式(C++)-行为型模式-中介者模式
c++·设计模式·中介者模式
iDao技术魔方3 小时前
DeepSeek TUI:原生 Rust 打造的终端 AI 编码 Agent
开发语言·人工智能·rust
jghhh013 小时前
认知无线电中基于能量检测的双门限频谱感知的 MATLAB 仿真
开发语言·matlab
Mr数据杨3 小时前
【Codex】用教案主体模块沉淀标准化教学设计内容
java·开发语言·django·codex·项目开发