如何实现标准库般强大的 C++ Vector?:从动态扩容到移动语义到迭代器全覆盖

在 C++ 中,std::vector 是最常用的动态数组容器。它具有高效的内存管理、动态扩容、随机访问等特点。在这篇博客中,我们将从零开始,实现一个功能强大、灵活、并且具有高性能的 Vector 类,具备 std::vector 的大部分功能,包括动态扩容、迭代器、模板支持、随机访问等,尽可能模仿 C++ 标准库中的 std::vector。本文将详细解释每个功能模块,并附加详细的解释和代码注释,以帮助初学者深入理解容器的内部工作原理和实现逻辑。

  
  

一、设计目标和规划

在设计一个 Vector 类时,我们需要考虑以下功能:

  • 动态扩容:支持自动增长容量,避免内存溢出。
  • 模板支持:容器应该能够存储任意类型的数据。
  • 迭代器:提供正向和反向迭代器,使得容器可以通过迭代器进行遍历。
  • 边界检查:防止访问越界,提高容器的健壮性。
  • 性能优化:通过使用移动语义和完美转发提升性能,减少不必要的拷贝。
  • 异常安全:确保在操作失败时不出现内存泄漏等问题。

让我们从基础的 Vector 实现开始,逐步添加这些功能。

注意:这篇博客所涉及的所有代码可以从我的代码仓库获得:https://git.lenyiin.com/Lenyiin/Vector

  
  

二、Vector 容器的基础实现

首先,我们需要定义一个 Vector 类来管理内部的数据。这个类包含动态分配的数组,维护当前元素数量和容量,并且提供基础的操作方法,比如插入、访问等。

  

2.1、Vector 容器的成员的设计与初始化

首先,我们定义一个 Vector 类的基础框架,它需要包括以下几个核心成员变量:

  • _start:指向存储实际元素的数组首地址。
  • _finish:指向存储实际元素的数组下一个可存储的地址。
  • _endofstorage:当前已分配的内存空间的末地址。
template<typename T>
class Vector {
public:
    // 默认构造
    Vector()    // 构造函数,初始化为空
        : _start(nullptr), _finish(nullptr), _endofstorage(nullptr)
    {
    }

    // 析构函数
    ~Vector()   // 析构函数,释放动态内存
    {
        if (_start)
        {
            delete[] _start;
        }
        _start = _finish = _endofstorage = nullptr;
    }

private:
    T* _start;
    T* _finish;
    T* _endofstorage;
};

详细解释:

  • 构造函数:在构造函数中,初始状态下 _start 为空,_finish 为 空,_endofstorage 也为空。
  • 析构函数:确保当 Vector 对象销毁时释放分配的内存。

  

2.2、获取容器状态

为了更好的了解容器状态,还需要添加获取容器状态的接口

// 获取当前元素有效个数
size_t size() const
{
    return _finish - _start;
}

// 获取当前容器容量
size_t capacity() const
{
    return _endofstorage - _start;
}

详细解释:

  • size()capacity() :分别返回当前的元素个数和容器容量,帮助用户了解容器的状态。

  

2.3、拷贝与赋值

C++ 中,拷贝一个对象时,默认的拷贝行为是浅拷贝,即仅复制对象的指针或引用。这对管理动态内存的类而言,可能会导致问题,例如多个对象指向同一块内存,导致重复释放或修改冲突。为避免这些问题,我们需要实现深拷贝。

2.3.1、拷贝构造函数

拷贝构造函数用于创建一个新对象,该对象是通过复制另一个现有对象生成的。对于 Vector 类,我们需要确保在拷贝时,新对象有自己独立的内存副本。

// 拷贝构造
Vector(const Vector<T>& v)
{
    _start = new T[v.capacity()];
    _finish = _start;
    _endofstorage = _start + v.capacity();

    for (size_t i = 0; i < v.size(); i++)
    {
        *_finish = v[i];
        ++_finish;
    }
}

详细解释:

  • 深拷贝:通过分配新内存来创建新对象的独立副本,而不是简单地复制指针。这样,两个 Vector 对象可以独立管理各自的内存,避免潜在的内存管理冲突。
  • 值得注意的是 *_finish = v[i]; 并不是浅拷贝,而是调用了 operator= 赋值运算,是深拷贝。

进阶:

  • 也可以复用插入函数 push_back
Vector(const Vector<T>& v)
    : _start(nullptr), _finish(nullptr), _endofstorage(nullptr)
{
    reserve(v.capacity());
    for (const auto& e : v)
    {
        push_back(e);
    }
}

2.3.2、赋值运算

赋值运算符用于将一个对象的内容复制到另一个已经存在的对象中。为了避免自赋值和内存泄漏,我们需要在实现赋值运算符时特别小心。

// 赋值运算符重载
Vector<T>& operator=(const Vector<T>& v)
{
    if (this != &v)
    {
        delete[] _start;
        _start = new T[v.capacity()];

        //memcpy(_start, v._start, sizeof(T) * v.size());   按字节拷贝,浅拷贝
        for (size_t i = 0; i < v.size(); i++)
        {
            _start[i] = v._start[i];    // 调用的是 operator= 深拷贝
        }

        _finish = _start + v.size();
        _endofstorage = _start + v.capacity();
    }
    return *this;
}

详细解释:

  • 自赋值检查:在赋值运算符实现中,首先检查是否为自赋值,即 this 指针是否与 v 相同。如果是自赋值,则无需进行任何操作,直接返回当前对象。
  • 内存管理:在分配新内存之前,记得释放当前对象所持有的旧内存,防止内存泄漏。
  • 深拷贝:与拷贝构造函数类似,通过分配新内存来存储字符串的副本,确保两个对象独立管理各自的内存。

进阶:

  • 也可以复用拷贝构造函数
// 进阶写法
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;
}

  

2.4、移动语义

C++11 引入的移动语义(Move Semantics)是提升性能的一个重要机制,允许在一定条件下避免不必要的深拷贝,从而提高程序性能。移动构造函数和移动赋值运算符是移动语义的核心。

2.4.1、移动构造函数

移动构造函数用于将资源从一个对象 “搬迁” 到另一个对象,而不是复制。这在避免不必要的内存分配和拷贝时非常有用。

// 移动构造函数
Vector(Vector&& v) noexcept 
    : _start(v._start), _finish(v._finish), _endofstorage(v._endofstorage)
{
    v._start = nullptr;
    v._finish = nullptr;
    v._endofstorage = nullptr;
}

详细解释:

  • 移动构造函数:将 v 对象的资源直接转移到当前对象(通过简单地复制指针),然后将 v_start, _finish, _endofstorage 重置为默认状态。通过窃取资源(即指针和相关的大小和容量),避免昂贵的拷贝操作。

  • noexcept:标记为 noexcept 的函数表示在其内部不会抛出异常。这对移动构造函数尤其重要,因为这确保了在某些情况下(如在标准容器中使用)不会因为抛出异常而触发回滚操作。

2.4.2、移动赋值运算

移动赋值运算用于将资源从一个对象 “搬迁” 到另一个已存在的对象中。

// 移动赋值运算符
Vector& operator=(Vector&& v) noexcept 
{
    if (this != &v) {
        delete[] _start;
        _start = v._start;
        _finish = v._start + v.size();
        _endofstorage = v._start + v.capacity();
        v._start = nullptr;
        v._finish = nullptr;
        v._endofstorage = nullptr;
    }
    return *this;
}

详细解释:

  • 资源搬迁:通过简单地复制指针,将 v 对象的资源转移到当前对象中,并释放当前对象的旧资源。然后,将 v 对象重置为默认状态,避免两个对象共享同一块内存。
  • 自赋值检查:和赋值运算符一样,首先检查是否为自赋值。

  

2.5、下标运算符重载

为了支持像数组一样通过下标访问 Vector 中的元素,我们需要重载 operator[]

T& operator[](size_t index) 
{
    if (index >= size()) 
    {
        throw std::out_of_range("Index out of range");
    }
    return _start[index];
}

const T& operator[](size_t index) const 
{
    if (index >= size()) 
    {
        throw std::out_of_range("Index out of range");
    }
    return _start[index];
}

详细解释:

  1. operator[] 重载:支持通过下标访问元素,并且提供 const 版本,确保容器在只读情况下的访问安全性。
  2. 越界检查:若访问的下标超出范围,抛出 std::out_of_range 异常,避免非法访问。

  

三、进阶功能

3.1、动态扩容

C++ 中 std::vector 最强大的功能之一是动态扩容。当容器中的元素超过当前容量时,它会自动分配更大的内存,并将已有的数据复制到新的内存区域。为此,我们实现一个 reserve 和 resize 函数,用于在需要时扩容。

void reserve(size_t newcapacity)
{
    if (newcapacity > capacity())
    {
        T* tmp = new T[newcapacity];    // 分配新内存
        size_t len = size();
        if (_start)
        {
            for (size_t i = 0; i < len; i++)
            {
                tmp[i] = std::move(_start[i]);  // 移动已有数据
            }
            delete[] _start;    // 释放旧的内存
        }
        // 更新指针
        _start = tmp;
        _finish = tmp + len;
        _endofstorage = tmp + newcapacity;
    }
}

// resize 不仅会开空间,还会初始化
void resize(size_t newsize, const T& val = T())
{
    if (newsize < size())
    {
        _finish = _start + newsize;
    }
    else
    {
        if (newsize > capacity())
        {
            reserve(newsize);
        }

        while (_finish < _start + newsize)
        {
            *_finish = val;
            ++_finish;
        }
    }
}

详细解释:

  • reserve 函数:用于重新分配内存,当当前容量不足时,分配一个新的数组并将原有数据复制过去。
  • resize 函数:用于重置有效数据大小,重置的时候还能进行初始化。当当前容量不足时,分配一个新的数组并将原有数据复制过去。
  • std::move:我们使用 std::move 来避免不必要的深度拷贝,提升性能。

  

3.2、插入元素 push_back

Vector 中添加元素时,需要判断是否需要扩容。如果当前元素数量已经等于容量,就调用 reserve 函数扩容。

void push_back(const T& data)
{
    if (_finish == _endofstorage)   // 若容量不足,则扩容
    {
        size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
        reserve(newcapacity);
    }

    *_finish = data;    // 插入新元素
    ++_finish;
}

详细解释:

  • push_back:当 _finish == _endofstorage 时,调用 reserve 扩容,然后插入新元素。

  • reserve 容量扩充策略:当容器为空时,初次扩容至 4,随后每次扩容翻倍。

  

3.3、增加迭代器支持

3.3.1、基础迭代器

std::vector 提供了强大的迭代器支持,允许用户使用 for-each 循环来遍历容器。我们可以通过自定义迭代器类,来实现这一功能。

typedef T* iterator;

iterator begin()
{
    return _start;
}

iterator end()
{
    return _finish;
}

详细解释:

  • iterator :封装了指针,使用默认解引用操作符 * 和递增操作符 ++,支持 for 循环遍历。

  • begin 与 end 函数:返回指向容器起始和末尾的迭代器,类似 std::vector::beginstd::vector::end

3.3.2、常量迭代器

在一些场景中,我们希望容器只能读取而不能修改数据。为此,我们可以实现 const_iterator 来保证只读遍历。

typedef const T* const_iterator;

const_iterator begin() const
{
    return _start;
}

const_iterator end() const
{
    return _finish;
}

详细解释:

  • const_iterator :与普通迭代器不同的是,它返回 const T*,确保数据不能被修改。

  • begin 与 end 函数:返回常量迭代器,支持只读遍历。

  

3.4、删除元素与清空操作

为了使我们的 Vector 容器更加完整,我们还需要支持删除元素和清空容器的操作。

void pop_back()
{
    assert(_start < _finish);

    --_finish;
}

void clear()
{
    _finish = _start;
}

详细解释:

  • pop_back 函数:移除最后一个元素,减小 _finish,但不改变已分配的容量。
  • clear 函数:将 _finish 设为 _start,保留容量但清空元素。

  

四、扩展功能

4.1、插入与删除

标准库的 std::vector 还支持在中间位置插入和删除元素。我们可以通过移动元素来实现这些功能。

iterator insert(iterator pos, const T& data)
{
    assert(pos <= _finish);

    if (_finish == _endofstorage)
    {
        size_t len = pos - _start;
        size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
        reserve(newcapacity);

        // 如果增容,原来的pos就失效了,这里需要重新计算位置
        pos = _start + len;
    }

    iterator end = _finish - 1;
    while (end >= pos)
    {
        *(end + 1) = *end;
        --end;
    }

    *pos = data;
    ++_finish;

    return pos;
}

iterator erase(iterator pos)
{
    assert(pos < _finish);

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

    return pos;
}

详细解释:

  • insert 函数:在指定位置插入元素,插入后,所有后续元素向后移动一位。
  • erase 函数:删除指定位置的元素,删除后,所有后续元素向前移动一位。

  

4.2、模板支持

我们通过使用模板,使 Vector 能够存储任意类型的元素。C++ 的模板机制允许我们实现对不同数据类型的支持,而无需为每种类型编写单独的代码。在上面的代码中,我们已经通过 template<typename T> 实现了模板支持。只需传递类型参数,即可为任何类型创建 Vector 容器。

Vector<int> intVector;
Vector<std::string> stringVector;

  

4.3、使用移动语义与完美转发

在 C++11 中引入的移动语义和完美转发是提升性能的重要工具,特别是在处理对象拷贝时。为了避免不必要的深度拷贝,我们可以使用 std::movestd::forward

void push_back(T&& data)    // 移动版本
{ 
    if (_finish == _endofstorage) 
    {
        reserve(capacity() == 0 ? 4 : capacity() * 2);
    }
    *_finish = std::move(data); // 使用 move 语义
    ++_finish;
}

详细解释:

  • push_back (移动版本):允许直接移动元素,而不是进行拷贝操作,大大提升了效率。

      

4.4、 完善边界检查与防止越界访问

为了使容器更加安全,我们可以在访问元素时进行边界检查,防止越界访问导致程序崩溃。

T& at(size_t index) 
{
    if (index >= size()) {
        throw std::out_of_range("Index out of bounds");
    }
    return _start[index];
}

详细解释:

  • at 函数:提供安全的数组访问方法,超出范围时抛出 std::out_of_range 异常。

  

五、完整实现代码和测试

5.1、Vector.hpp

新建头文件 Vector.hpp

#pragma once

#include <iostream>
#include <assert.h>

using namespace std;

namespace Lenyiin
{
    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;
        }

        size_t size() const
        {
            return _finish - _start;
        }

        size_t capacity() const
        {
            return _endofstorage - _start;
        }

        // 默认构造
        Vector()
            : _start(nullptr), _finish(nullptr), _endofstorage(nullptr)
        {
        }

        // 拷贝构造
        //Vector(const Vector<T>& v)
        //{
        //  _start = new T[v.capacity()];
        //  _finish = _start;
        //  _endofstorage = _start + v.capacity();

        //  for (size_t i = 0; i < v.size(); i++)
        //  {
        //      *_finish = v[i];
        //      ++_finish;
        //  }
        //}

        // 进阶写法
        Vector(const Vector<T>& v)
            : _start(nullptr), _finish(nullptr), _endofstorage(nullptr)
        {
            reserve(v.capacity());
            for (const auto& e : v)
            {
                push_back(e);
            }
        }

        // 赋值运算符重载
        //Vector<T>& operator=(const Vector<T>& v)
        //{
        //  if (this != &v)
        //  {
        //      delete[] _start;
        //      _start = new T[v.capacity()];

        //      //memcpy(_start, v._start, sizeof(T) * v.size());   按字节拷贝,浅拷贝
        //      for (size_t i = 0; i < v.size(); i++)
        //      {
        //          _start[i] = v._start[i];    // 调用的是 operator= 深拷贝
        //      }

        //      _finish = _start + v.size();
        //      _endofstorage = _start + v.capacity();
        //  }
        //  return *this;
        //}

        // 进阶写法
        void swap(Vector<T>& v)   // 自己写的swap是浅拷贝,代价小
        {
            std::swap(_start, v._start);
            std::swap(_finish, v._finish);
            std::swap(_endofstorage, v._endofstorage);
        }

        Vector<T>& operator=(Vector<T> v)
        {
            swap(v);    // 库里面的swap是深拷贝,代价极大
            return *this;
        }

        // 移动构造函数
        Vector(Vector&& v) noexcept
            : _start(v._start), _finish(v._finish), _endofstorage(v._endofstorage)
        {
            v._start = nullptr;
            v._finish = nullptr;
            v._endofstorage = nullptr;
        }

        // 移动赋值运算符
        Vector& operator=(Vector&& v) noexcept
        {
            if (this != &v) {
                delete[] _start;
                _start = v._start;
                _finish = v._start + v.size();
                _endofstorage = v._start + v.capacity();
                v._start = nullptr;
                v._finish = nullptr;
                v._endofstorage = nullptr;
            }
            return *this;
        }

        // 析构函数
        ~Vector()
        {
            if (_start)
            {
                delete[] _start;
            }
            _start = _finish = _endofstorage = nullptr;
        }

        // 下标运算符重载
        T& operator[](size_t index)
        {
            if (index >= size())
            {
                throw std::out_of_range("Index out of range");
            }
            return _start[index];
        }

        const T& operator[](size_t index) const
        {
            if (index >= size())
            {
                throw std::out_of_range("Index out of range");
            }
            return _start[index];
        }

        // 动态扩容
        void reserve(size_t newcapacity)
        {
            if (newcapacity > capacity())
            {
                T* tmp = new T[newcapacity];    // 分配新内存
                size_t len = size();
                if (_start)
                {
                    for (size_t i = 0; i < len; i++)
                    {
                        tmp[i] = std::move(_start[i]);  // 移动已有数据
                    }
                    delete[] _start;    // 释放旧的内存
                }
                // 更新指针
                _start = tmp;
                _finish = tmp + len;
                _endofstorage = tmp + newcapacity;
            }
        }

        // resize 不仅会开空间,还会初始化
        void resize(size_t newsize, const T& val = T())
        {
            if (newsize < size())
            {
                _finish = _start + newsize;
            }
            else
            {
                if (newsize > capacity())
                {
                    reserve(newsize);
                }

                while (_finish < _start + newsize)
                {
                    *_finish = val;
                    ++_finish;
                }
            }
        }

        void push_back(const T& data)
        {
            if (_finish == _endofstorage)
            {
                size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
                reserve(newcapacity);
            }

            *_finish = data;
            ++_finish;
        }

        // 移动版本
        void push_back(T&& data)
        {
            if (_finish == _endofstorage)
            {
                reserve(capacity() == 0 ? 4 : capacity() * 2);
            }
            *_finish = std::move(data); // 使用 move 语义
            ++_finish;
        }

        // 更安全的访问方式
        T& at(size_t index)
        {
            if (index >= size()) {
                throw std::out_of_range("Index out of bounds");
            }
            return _start[index];
        }

        void pop_back()
        {
            assert(_start < _finish);

            --_finish;
        }

        void clear()
        {
            _finish = _start;
        }

        iterator insert(iterator pos, const T& data)
        {
            assert(pos <= _finish);

            if (_finish == _endofstorage)
            {
                size_t len = pos - _start;
                size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
                reserve(newcapacity);

                // 如果增容,原来的pos就失效了,这里需要重新计算位置
                pos = _start + len;
            }

            iterator end = _finish - 1;
            while (end >= pos)
            {
                *(end + 1) = *end;
                --end;
            }

            *pos = data;
            ++_finish;

            return pos;
        }

        iterator erase(iterator pos)
        {
            assert(pos < _finish);

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

            return pos;
        }

    private:
        iterator _start;
        iterator _finish;
        iterator _endofstorage;
    };
}

  

5.2、Vector.cpp

新建测试文件 Vector.cpp

#include "Vector.hpp"
#include <string>

using namespace Lenyiin;

void print_Vector(const Vector<int>& v)
{
    Vector<int>::const_iterator it = v.begin();
    while (it != v.end())
    {
        cout << *it << " ";
        ++it;
    }
    cout << endl;
}

// Vector 容器遍历
void test1()
{
    Vector<int> v;

    // 插入
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    v.push_back(5);

    // 查看容量
    cout << v.size() << endl;
    cout << v.capacity() << endl << endl;;

    // 1. 下标运算符 [] 遍历
    cout << "1. 下标运算符 [] 遍历 \t\t";
    for (size_t i = 0; i < v.size(); i++)
    {
        cout << v[i] << " ";
    }
    cout << endl;

    // 2. 迭代器遍历
    cout << "2. 迭代器遍历 \t\t\t";
    Vector<int>::iterator it = v.begin();
    while (it != v.end())
    {
        cout << *it << " ";
        ++it;
    }
    cout << endl;

    // 3. const_iterator 迭代器遍历
    cout << "3. const_iterator 迭代器遍历 \t";
    print_Vector(v);

    // 4. 范围 for 遍历
    cout << "4. 范围 for 遍历 \t\t";
    for (auto& e : v)
    {
        cout << e << " ";
    }
    cout << endl;

    // 4. 范围 for 遍历 const
    cout << "5. 范围 for 遍历 const \t\t";
    for (const auto& e : v)
    {
        cout << e << " ";
    }
    cout << endl;
}

void test2()
{
    Vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    v.push_back(5);
    v.push_back(6);
    print_Vector(v);
    cout << v.size() << endl;
    cout << v.capacity() << endl << endl;;

    // 随即插入
    v.insert(v.begin(), 0);
    print_Vector(v);

    // 删除所有偶数
    Vector<int>::iterator it = v.begin();
    while (it != v.end())
    {
        if (*it % 2 == 0)
        {
            it = v.erase(it);
        }
        else
        {
            it++;
        }
    }
    print_Vector(v);
}

void test3()
{
    Vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    v.push_back(5);
    v.push_back(6);
    v.push_back(7);

    print_Vector(v);
    cout << v.size() << endl;
    cout << v.capacity() << endl << endl;;

    // resize
    v.resize(4);
    print_Vector(v);
    cout << v.size() << endl;
    cout << v.capacity() << endl << endl;;

    v.resize(8);
    print_Vector(v);
    cout << v.size() << endl;
    cout << v.capacity() << endl << endl;;

    v.resize(15);
    print_Vector(v);
    cout << v.size() << endl;
    cout << v.capacity() << endl << endl;;

    // 清除
    v.clear();
    print_Vector(v);
    cout << v.size() << endl;
    cout << v.capacity() << endl << endl;;

    // reserve
    v.reserve(20);
    print_Vector(v);
    cout << v.size() << endl;
    cout << v.capacity() << endl << endl;;
}

void test4()
{
    // 默认构造
    Vector<int> v1;
    v1.push_back(1);
    v1.push_back(2);
    v1.push_back(3);
    v1.push_back(4);
    v1.push_back(5);
    v1.push_back(6);
    v1.push_back(7);
    print_Vector(v1);

    // 拷贝构造
    Vector<int> v2(v1);
    print_Vector(v2);

    Vector<int> v3;
    v3.push_back(10);
    v3.push_back(20);
    v3.push_back(30);
    v3.push_back(40);

    // 赋值
    v1 = v3;
    print_Vector(v1);
    print_Vector(v3);
}

void test5()
{
    // 模板
    Vector<string> v;
    v.push_back("111");
    v.push_back("222");
    v.push_back("333");
    v.push_back("444");

    for (auto e : v)
    {
        cout << e << " ";
    }
    cout << endl;
}

int main()
{
    //test1();
    //test2();
    //test3();
    test4();
    //test5();

    return 0;
}

  

六、总结

通过这篇博客,我们从最基础的存储与管理机制开始,逐步构建了一个强大且灵活的 Vector 容器,具备动态扩容、模板支持、迭代器、常量迭代器、移动语义、边界检查等高级功能,能够媲美 std::vector。在这一过程中,我们学会了如何高效管理内存、优化性能并保证容器的安全性。此外,我们还增加了随机访问、边界检查、插入删除、异常处理等高级功能。通过这篇文章的学习,你应该对 C++ 容器的内部实现有了更深入的理解,并掌握了构建自定义容器的关键技术。

  

希望这篇博客对您有所帮助,也欢迎您在此基础上进行更多的探索和改进。如果您有任何问题或建议,欢迎在评论区留言,我们可以共同探讨和学习。更多知识分享可以访问我的个人博客网站 : https://blog.lenyiin.com/ 。本博客所涉及的代码也可以访问我的 git 仓库获取 :https://git.lenyiin.com/Lenyiin/Vector

Comments

No comments yet. Why don’t you start the discussion?

发表回复