C++自定义(手撕)vector类实现过程

 更新时间:2025年09月23日 16:04:13   作者:Truelon  
文章介绍了C++中std::vector的简化实现,涵盖模板类定义、动态数组管理、构造析构函数、深拷贝机制、迭代器及容量操作等核心内容,旨在通过手动实现理解其内存管理原理和底层实现逻辑

引言

在C++中,std::vector 是一个非常强大的容器,能够自动管理其内部存储空间的大小,使得程序员无需手动处理内存分配和释放。然而,理解 std::vector 内部工作原理对于提高编程技能至关重要。

通过自己实现一个简化版的 vector 类,我们可以更好地掌握其背后的核心概念。

类定义与成员变量

我们首先定义了一个模板类 vector,它接受一个类型参数 T。此外,我们定义了三个成员变量:

  • _data:指向动态分配的数组的指针。
  • _size:当前元素的数量。
  • _capacity:分配的数组可以容纳的最大元素数量。
template<typename T>
class vector {
public:
    // ... 公共接口 ...

private:
    T* _data;
    size_t _size;
    size_t _capacity;
};

构造函数

  • 默认构造函数:初始化 _datanullptr_size_capacity0
  • 带参数构造函数:接收一个元素数量和可选的初始值,创建一个初始化了特定数量元素的 vector
  • 拷贝构造函数:执行深拷贝,确保每个 vector 对象都有自己的数据副本。
vector() : _data(nullptr), _size(0), _capacity(0) {}
explicit vector(size_t count, const T& value = T()) { /* 初始化逻辑 */ }
vector(const vector& vec) { /* 深拷贝逻辑 */ }

析构函数

析构函数负责释放由 _data 指向的动态分配的内存。

~vector() {
    delete[] _data;
}

深拷贝构造函数与赋值操作

为了防止浅拷贝导致的问题(例如,多个 vector 对象指向同一块内存),我们实现了深拷贝构造函数和赋值操作符。

vector(const vector& vec) { /* 深拷贝逻辑 */ }
vector& operator=(const vector& vec) { /* 深拷贝赋值逻辑 */ }

迭代器

提供 begin()end() 方法来获取指向向量起始和结束位置的迭代器,分别用于非常量和常量上下文。

T* begin() { return _data; }
T* end() { return _data + _size; }
const T* begin() const { return _data; }
const T* end() const { return _data + _size; }

容量与大小

size() 返回当前元素数量,而 capacity() 返回数组的最大容量。

size_t size() const { return _size; }
size_t capacity() const { return _capacity; }

元素操作

push_back()pop_back() 用于在向量末尾添加或移除元素。insert()erase() 用于在任意位置插入或删除元素。

void push_back(T val);
void pop_back();
void insert(size_t index, const T& value);
void erase(size_t index);

辅助函数

resize() 函数用于在必要时调整向量的容量。

void resize(size_t new_capacity);

完整代码

#include <iostream>
#include <vector>

// 定义一个名为mv的命名空间
namespace mv {
    // 定义一个模板类vector
    template<typename T>
    class vector {
    public:
        // 定义类型别名
        typedef T val_type;
        typedef val_type* iterator;

        // 默认构造函数
        vector() : _data(nullptr), _size(0), _capacity(0) {}

        // 析构函数,用于释放动态分配的内存
        ~vector() {
            delete[] _data;
        }

        // 带参数的构造函数,初始化vector大小和默认值
        explicit vector(size_t count, const val_type& value = val_type())
            : _data(new val_type[count]), _size(count), _capacity(count) {
            for (size_t i = 0; i < count; ++i) {
                _data[i] = value;
            }
        }

        // 深拷贝构造函数,避免浅拷贝的问题
        vector(const vector& vec) {
            _capacity = vec._capacity;
            _data = new val_type[_capacity]; // 分配新的内存空间
            for (size_t i = 0; i < vec._size; ++i) {
                _data[i] = vec._data[i];
            }
            _size = vec._size;
        }

        // 提供const和非const版本的begin和end方法
        iterator begin() { return _data; }
        iterator end() { return _data + _size; }
        iterator begin() const { return _data; }
        iterator end() const { return _data + _size; }

        // 返回vector的大小和容量
        size_t size() const { return _size; }
        size_t capacity() const { return _capacity; }

        // 在末尾添加一个元素
        void push_back(val_type val) {
            if (_size == _capacity) {
                resize(_capacity == 0 ? 1 : _capacity * 2);
            }
            _data[_size++] = val;
        }

        // 移除最后一个元素
        void pop_back() {
            if (_size > 0)
                --_size;
        }

        // 在指定位置插入一个元素
        void insert(size_t index, const val_type& value) {
            if (_size == _capacity) {
                resize(_capacity == 0 ? 1 : _capacity * 2);
            }
            if (index > _size) {
                std::cout << "Index out of range in insert()";
            }
            for (size_t i = _size; i > index; --i) {
                _data[i] = _data[i - 1];
            }
            _data[index] = value;
            ++_size;
        }

        // 删除指定位置的元素
        void erase(size_t index) {
            if (index >= _size) {
                std::cout << "Index out of range in erase()";
            }
            for (size_t i = index; i < _size - 1; ++i) {
                _data[i] = _data[i + 1];
            }
            --_size;
        }

        // 判断vector是否为空
        bool empty() { return _size == 0; }

        // 下标操作符,返回指定位置的元素
        val_type& operator[](size_t index) { return _data[index]; }

        // 比较两个vector是否相等
        bool operator==(const vector& vec) const {
            if (_size != vec._size) return false;
            for (size_t i = 0; i < _size; ++i) {
                if (_data[i] != vec._data[i]) return false;
            }
            return true;
        }

        // 赋值操作符,实现深拷贝
        vector& operator=(const vector& vec) {
            if (this != &vec) { // 防止自赋值
                delete[] _data; // 释放原有资源
                _capacity = vec._capacity;
                _data = new val_type[_capacity]; // 分配新资源
                for (size_t i = 0; i < vec._size; ++i) {
                    _data[i] = vec._data[i];
                }
                _size = vec._size;
            }
            return *this;
        }

    private:
        // 调整vector的容量
        void resize(size_t new_capacity) {
            val_type* new_data = new val_type[new_capacity];
            for (size_t i = 0; i < _size; ++i) {
                new_data[i] = _data[i];
            }
            delete[] _data;
            _data = new_data;
            _capacity = new_capacity;
        }

        // 成员变量
        val_type* _data;
        size_t _size;
        size_t _capacity;
    };
}

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Opencv下载和导入Visual studio2022的实现步骤

    Opencv下载和导入Visual studio2022的实现步骤

    本文主要介绍了Opencv下载和导入Visual studio2022的实现步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05
  • 16种C语言编译警告(Warning)类型的解决方法

    16种C语言编译警告(Warning)类型的解决方法

    由于编译的警告各种各样,根本不可以一一罗列出来,下面只是列举出比较典型的十六种警告,还有一些警告,大家只要根据字面意思,就可以很快的查找出来,并解决之。希望对大家有所帮助。
    2014-08-08
  • C++中将Char转换成String的4种方法

    C++中将Char转换成String的4种方法

    本文主要介绍了C++中将Char转换成String的4种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-03-03
  • CStdioFile的用法详细解析

    CStdioFile的用法详细解析

    CStdioFile 不支持Duplicate,LockRange,和UnlockRange 这几个CFile 函数。如果在CStdioFile 中调用了这几个函数,将会出现CNoSupported 异常
    2013-09-09
  • c语言中回调函数的使用以及实际作用详析

    c语言中回调函数的使用以及实际作用详析

    回调函数就是一个通过函数指针调用的函数,如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数,这篇文章主要给大家介绍了关于c语言中回调函数的使用以及实际作用的相关资料,需要的朋友可以参考下
    2021-07-07
  • 用C++实现一个命令行进度条的示例代码

    用C++实现一个命令行进度条的示例代码

    这篇文章主要介绍了用C++实现一个命令行进度条的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-04-04
  • Objective-C的内省(Introspection)用法小结

    Objective-C的内省(Introspection)用法小结

    这篇文章主要介绍了Objective-C的内省(Introspection)用法,这是面向对象语言和环境的一个强大特性,需要的朋友可以参考下
    2014-07-07
  • C++中类的构造函数初始值列表解读

    C++中类的构造函数初始值列表解读

    这篇文章主要介绍了C++中类的构造函数初始值列表,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11
  • C语言switch语句详解

    C语言switch语句详解

    这篇文章主要为大家介绍了C语言switch语句,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2021-12-12
  • c语言如何输出一个n行m列的图形

    c语言如何输出一个n行m列的图形

    这篇文章主要介绍了c语言如何输出一个n行m列的图形问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-06-06

最新评论