【C++】手动实现C++ vector容器:深入理解动态数组的工作原理

news2024/12/25 4:37:06

💯个人主页: 起名字真南
💯个人专栏:【数据结构初阶】 【C语言】 【C++】 【OJ题解】

请添加图片描述

目录

  • 1. 引言
  • 2. 实现思路
  • 3. `vector` 容器的代码实现
  • 4. 代码详解
    • 4.1 构造与析构函数
    • 4.2 容量管理
    • 4.3 迭代器与访问操作
    • 4.4 增删操作
  • 5.测试代码
  • 6. 时间和空间复杂度分析
  • 7. 总结

1. 引言

vector 是 C++ 标准模板库(STL)中最常用的动态数组容器。它不仅提供了自动扩容、快速访问、灵活增删等功能,还能高效地管理内存。本篇文章将带大家实现一个简化版的 vector,包含动态扩容、元素插入删除、访问等操作,以此深入理解其内部实现原理,尤其是动态数组的管理机制。

2. 实现思路

我们将实现的 vector 具有如下核心功能:

  1. 构造与析构:支持多种方式的构造,并在对象销毁时正确释放内存。
  2. 容量管理:包括扩容、调整大小等操作。
  3. 元素增删:支持尾部增删以及在任意位置插入删除元素。
  4. 迭代器与访问操作:提供迭代器和下标访问方式。

3. vector 容器的代码实现

以下是完整的代码实现,功能完备,包含了构造、析构、拷贝、赋值重载、容量管理、增删操作和元素访问等基本操作:

#pragma once

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

namespace wzr 
{
    template<class T>
    class vector 
    {
    public:
        typedef T* iterator;
        typedef const T* const_iterator;

        // 默认构造函数
        vector() 
        : _start(nullptr)
        , _finish(nullptr),
         _endOfStorage(nullptr)
         {}

        // 构造函数:构造n个value
        vector(size_t n, const T& value = T())
            : _start(nullptr)
            , _finish(nullptr)
            , _endOfStorage(nullptr) 
            {
            reserve(n);
            while (n--) 
            {
                push_back(value);
            }
  //其实我们会发现这两串代码会有一些冗余,当我们使用vector(10,1)
  //编译器在编译的时候就已经将T实例化成int类型,
  //并且编译器会认为10,1是int,如果两个类型一致就会选择是区间构造,会报错。
        		vector(int n, const T & value = T())
				:_start(new T[n])
				, _finish(_start + n)
				, _endOfStorage(_finish)
			{
				reserve(n);
				for (int i = 0; i < n; i++)
				{
					_start[i] = value;
				}
			}

        // 拷贝构造函数
        vector(const vector<T>& v) 
        	: _start(nullptr)
       		, _finish(nullptr)
        	, _endOfStorage(nullptr) 
        	{
            reserve(v.capacity());
            iterator it = begin();
            const_iterator vit = v.cbegin();
            while (vit != v.cend()) {
                *it++ = *vit++;
            }
            _finish = it;
        }
 //如果使用iterator作为迭代器进行区间初始化构造,
 //那么容器就是能是vector
//重新声明迭代器,迭代区间[first, last)可以是任意容量的迭代器
	template<class InputIterator>
	vector(InputIterator first, InputIterator last)
	{
		while (first != last)
		{
			push_back(*first);
			++first;
		}
	}

        // 赋值操作符重载(采用拷贝交换优化)
        vector<T>& operator=(vector<T> v) 
        {
            swap(v);
            return *this;
        }

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

        // 迭代器
        iterator begin() 
        { 
        	return _start;
         }
        iterator end() 
        {
         	return _finish; 
         }
        const_iterator cbegin() const
         { 
         	return _start; 
         }
        const_iterator cend() const 
        { 
        	return _finish; 
        }

        // 容量管理
        size_t size() const 
        { 
        	return _finish - _start; 
        }
        size_t capacity() const 
        { 
        	return _endOfStorage - _start;
         }
        bool empty() const 
        { 
        	return _start == _finish;
         }

        // 预留空间
        void reserve(size_t n) 
        {
            if (n > capacity()) {
                size_t oldSize = size();
                T* tmp = new T[n];
                if (_start) {
                    for (size_t i = 0; i < oldSize; i++) {
                        tmp[i] = _start[i];
                    }
                    delete[] _start;
                }
                _start = tmp;
                _finish = _start + oldSize;
                _endOfStorage = _start + n;
            }
        }

        // 改变大小
        void resize(size_t n, const T& value = T()) 
        {
            if (n <= size()) {
                _finish = _start + n;
            } else {
                if (n > capacity()) {
                    reserve(n);
                }
                iterator it = _finish;
                _finish = _start + n;
                while (it != _finish) {
                    *it = value;
                    it++;
                }
            }
        }

        // 元素访问
        T& operator[](size_t pos)
         {
            assert(pos < size());
            return _start[pos];
        }
        const T& operator[](size_t pos) const 
        {
            assert(pos < size());
            return _start[pos];
        }

        T& front()
         {
         	 return *_start;
           }
        const T& front() const
         { 
         	return *_start; 
         }
        T& back()
         {
          	return *(_finish - 1); 
          }
        const T& back() const
         { 
         	return *(_finish - 1);
          }

        // 增删操作
        void push_back(const T& value) 
        { 
        	insert(end(), value); 
        }
        void pop_back() 
        { 
        	erase(end() - 1); 
        }

        // 交换两个vector
        void swap(vector<T>& v) 
        {
            std::swap(_start, v._start);
            std::swap(_finish, v._finish);
            std::swap(_endOfStorage, v._endOfStorage);
        }

        // 插入
        iterator insert(iterator pos, const T& x)
         {
            assert(pos <= _finish);
            if (_finish == _endOfStorage) {
                size_t newcapacity = (capacity() == 0 ? 1 : 2 * capacity());
                reserve(newcapacity);
                pos = _start + size();
            }
            iterator end = _finish - 1;
            while (end >= pos) {
                *(end + 1) = *end;
                --end;
            }
            *pos = x;
            ++_finish;
            return pos;
        }

        // 删除
        iterator erase(iterator pos)
         {
            iterator begin = pos + 1;
            while (begin != end()) 
            {
                *(begin - 1) = *begin;
                begin++;
            }
            --_finish;
            return pos;
        }

    private:
        iterator _start;          // 数据起始指针
        iterator _finish;         // 有效数据的结束指针
        iterator _endOfStorage;   // 总容量的结束指针
    };
}

4. 代码详解

4.1 构造与析构函数

  • vector():默认构造函数,初始化指针为 nullptr,用于构造空的 vector
  • vector(size_t n, const T& value = T()):构造一个大小为 nvector,并用 value 初始化每个元素。调用 reserve(n) 分配空间,再通过 push_back 插入元素。
  • vector(const vector<T>& v):拷贝构造函数。分配与 v 相同的空间后,逐个拷贝 v 中的元素。
  • vector(InputIterator first,InputIterator last):使用迭代器区间去构造函数。
  • ~vector():析构函数。释放动态分配的内存,并将所有指针置为 nullptr

4.2 容量管理

  • reserve(size_t n):扩容函数。若 n 大于当前容量,则分配一个大小为 n 的新空间,将原数据拷贝至新空间,并释放旧空间。
  • resize(size_t n, const T& value = T()):调整 vector 大小。若 n 小于当前大小,则只需调整 _finish。若 n 大于容量,则扩容并初始化新增元素。

4.3 迭代器与访问操作

  • begin()end():返回 _start_finish,用于迭代 vector
  • operator[]:通过下标访问元素,并通过 assert 检查越界访问。
  • front()back():返回首尾元素的引用,支持首尾元素的快速访问。

4.4 增删操作

  • push_back(const T& value):在尾部插入元素 value。若容量不足,调用 reserve 扩容。
  • pop_back():删除最后一个元素,通过调整 _finish 指针实现。
  • insert(iterator pos, const T& x):在指定位置插入元素 x。若容量不足,则扩容;随后将 [pos, end) 的数据右移,腾出插入位置。
  • erase(iterator pos):删除指定位置的元素。将 [pos + 1, end) 的数据左移一位以覆盖删除位置,更新 _finish 指针。

5.测试代码

#include"Vector.h"

namespace wzr
{
	void Test01()
	{
		vector<int> v1;
		vector<int> v2(10, 6);

		int array[] = { 1,2,3,4,5 };
		vector<int> v3(array, array + sizeof(array) / sizeof(array[0]));

		vector<int> v4(v3);

		for (size_t i = 0; i < v2.size(); i++)
		{
			cout << v2[i] << " ";
		}
		cout << endl;
		auto it = v3.begin();
		while (it != v3.end())
		{
			cout << *it << " ";
			it++;
		}
		cout << endl;

		for (auto itt : v4)
		{
			cout << itt << " ";
		}
		cout << endl;
	}
	void Test02()
	{
		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;
		cout << v.front() << endl;
		cout << v.back() << endl;
		cout << v[0] << endl;

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

		v.pop_back();
		v.pop_back();

		v.insert(v.begin(), 0);
		for (auto e : v)
		{
			cout << e << " ";
		}
		cout << endl;

		v.erase(v.begin() + 1);
		for (auto e : v)
		{
			cout << e << " ";
		}
		cout << endl;
	}
}
int main()
{
	//wzr::Test01();
	wzr::Test02();
	return 0;
}

6. 时间和空间复杂度分析

  • push_back:均摊时间复杂度为O(1),因为扩容后插入操作是常数时间的。
  • pop_back:O(1)。
  • resize:O(n)。
  • inserterase:最坏情况时间复杂度为O(n),因为需要移动大量数据。

7. 总结

通过对各个函数的详细解析,我们手动实现了一个简化版的 vector,展示了 C++ 标准库中 vector 的核心功能。希望通过这篇文章,大家能更好地理解 vector 容器

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2234829.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深入探讨钉钉与金蝶云星空的数据集成技术

钉钉报销数据集成到金蝶云星空的技术案例分享 在企业日常运营中&#xff0c;行政报销流程的高效管理至关重要。为了实现这一目标&#xff0c;我们采用了轻易云数据集成平台&#xff0c;将钉钉的行政报销数据无缝对接到金蝶云星空的付款单系统。本次案例将重点介绍如何通过API接…

Appium环境搭建/使用教程(图文超详细)

一&#xff0c;环境依赖JDK和Android SDK搭建 (1) JDK: 下载安装&#xff08;推荐java8版本,其他版本不兼容&#xff0c;会导致appiumServer启动不了) 下载地址&#xff1a;http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html根据自己的系…

大数据-209 数据挖掘 机器学习理论 - 梯度下降 梯度下降算法调优

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

模拟实现strcat函数

1.strcat的作用 char * strcat ( char * destination, const char * source ); 作用&#xff1a;将源字符串的附加到目标字符串中。目标字符串中的终止空字符将被源字符串的第一个字符替换&#xff0c;并且在将两个字符串连接形成的新字符串的末尾将包含一个空字符。 destina…

c++多线程QThreadpool调用Python脚本时崩溃报错的解决方案二

问题 还是c Qt多线程调用Python脚本时的问题。使用QthreadPool的方式调用&#xff0c;按照上次的解决方案也可以实现&#xff0c;虽然可能不出现崩溃问题。但是仍然有很大可能会出现死锁。即调入函数后&#xff0c;再无输出&#xff0c;变成一个黑洞… 解决方案 因为我使用的…

知从科技受邀出席ARM日产技术日

10月29日&#xff0c;上海知从科技有限公司受 ARM 之邀&#xff0c;参与了由其主办的日产技术日活动。此次活动在日本神奈川县厚木市的日产技术中心盛大举行&#xff0c;这一活动汇聚了行业内的前沿技术与精英人才&#xff0c;成为科技创新技术交流的重要平台。 知从科技积极参…

设计模式讲解02—责任链模式(Chain)

1. 概述 定义&#xff1a;责任链模式是一种行为型模式&#xff0c;在这个模式中&#xff0c;通常创建了一个接收者对象的链来处理请求&#xff0c;该请求沿着链的顺序传递。直到有对象处理该请求为止&#xff0c;从而达到解耦请求发送者和请求处理者的目的。 解释&#xff1a;责…

Vue项目引入侧边导航栏

Vue项目引入侧边导航栏 侧边导航栏能够非常方便进行信息检索&#xff0c;这一款不错的侧边导航栏&#xff1a;vue-side-catalog&#xff0c;基本上能满足快速检索的需求 安装 官网 首先需要进入** vue-side-catalog**的官网&#xff0c;然后下载对应的源码&#xff0c;下载…

【大数据学习 | kafka】kafka的偏移量管理

1. 偏移量的概念 消费者在消费数据的时候需要将消费的记录存储到一个位置&#xff0c;防止因为消费者程序宕机而引起断点消费数据丢失问题&#xff0c;下一次可以按照相应的位置从kafka中找寻数据&#xff0c;这个消费位置记录称之为偏移量offset。 kafka0.9以前版本将偏移量信…

专业 UI 设计公司:为您开启交互设计新征程

在当今数字化时代&#xff0c;UI设计不仅是产品外观的呈现&#xff0c;更是用户体验的核心组成部分。专业的UI设计公司凭借其深厚的设计底蕴、前沿的设计理念以及丰富的项目经验&#xff0c;能够为企业开启全新的交互设计征程&#xff0c;提升产品的市场竞争力。以下是对一家专…

【神经科学学习笔记】基于分层嵌套谱分割(Nested Spectral Partition)模型分析大脑网络整合与分离的学习总结

一、前言 1.学习背景 最近在学习脑网络分析方法时&#xff0c;笔者偶然读到了一篇发表在Physical Review Letters上的文章&#xff0c;文章介绍了一种名为嵌套谱分割(Nested-Spectral Partition, NSP)的方法&#xff0c;用于研究大脑功能网络的分离和整合特性。 传统的脑网络分…

初识C++(上) -- C++的关键字、命名空间、缺省参数以及函数的重载

目录 一、C的关键字&#xff08;C98&#xff09; 二、命名空间 1、命名冲突 2、命名空间 2.1 命名空间的定义 (1). 命名空间定义的例子以及命名空间的嵌套&#xff1a; (2). 同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中&#xff1a; 2…

计算机网络socket编程(1)_UDP网络编程实现echo server

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 计算机网络socket编程(1)_UDP网络编程实现echo server 收录于专栏【计算机网络】 本专栏旨在分享学习计算机网络的一点学习笔记&#xff0c;欢迎大家在评论区交…

[安洵杯 2019]easy_web 详细题解

知识点: 编码转换 命令执行 linux空格_关键字绕过 打开页面 发现url 是 /index.php?imgTXpVek5UTTFNbVUzTURabE5qYz0&cmd 有img参数和cmd参数 cmd参数是没赋值的,随便赋值为123456 页面没有反应 鼠标移动到图片下面时发现有东西,当然直接查看页面源代码也可以发现 尝…

免费,基于React + ECharts 国产开源 IoT 物联网 Web 可视化数据大屏

文末查看开源项目地址 Light Chaser 是一款国产开源免费的基于 React18、Vite5、TypeScript5 技术栈实现的 Web 可视化大屏设计工具&#xff0c;支持Docker方式部署&#xff0c;支持MySQL、PostgreSQL、SQL Server、Oracle 数据源。 你可以简单快速地搭建数据可视化展示、数据报…

Linux服务管理-DHCP

DHCP DHCP&#xff08;Dynamic Host Configuration Protocol&#xff0c;动态主机配置协议&#xff09;是一个局域网的网络协议&#xff0c;它允许服务器自动地将IP地址和其他网络配置参数分配给网络中的计算机。DHCP极大地简化了网络管理&#xff0c;尤其是当大量设备需要接入…

如何使用Netdata部署高性能的服务器监控平台

简介 Netdata 是一个开源的、实时的性能和健康监控工具&#xff0c;专为系统、应用程序、SNMP 设备等而设计。它以其高度交互的 Web 仪表板和极低的资源开销而闻名。 主要特点&#xff1a;实时监控、全面监控、零配置、轻量级、交互式仪表板、可扩展性、警报和通知、分布式监…

【MySQL】深度学习与解析 : 库的操作知识整合

前言&#xff1a;本节内容是MySQL库的操作&#xff0c; 内容较少&#xff0c; 大体内容为创建库、删除库、修改库、库备份操作。 ps:本节内容适合安装了MySQL的友友们进行观看&#xff0c; 实操更有利于记住哦。 目录 创建数据库 查看数据库列表 创建数据库 删除数据库 …

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-11-01

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-11-01 目录 文章目录 计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-11-01目录1. A Perspective for Adapting Generalist AI to Specialized Medical AI Applications and Their Challenges2. Synergi…

白杨SEO:百度在降低个人备案类网站搜索关键词排名和流量?怎样应对?【参考】

很久没有写百度或者网站这块内容了&#xff0c;一是因为做百度网站朋友越来越少&#xff0c;不管是个人还是企业&#xff1b;二是百度上用户搜索与百度给到网站的流量都越来越少。 为什么想到今天又来写这个呢&#xff1f;因为上个月有个朋友来咨询我说网站百度排名全没了&…