当前位置: 首页 > article >正文

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

作为C标准模板库STL中最基础、最常用的容器之一vector提供了动态数组的功能。今天我们将深入探讨如何从零实现一个完整的vector容器理解其内部工作原理和设计思想。代码解释C Vector模板类实现代码整体功能和主要作用C动态数组vector模板类实现其主要功能包括动态数组管理自动扩容的动态数组容器类型安全通过模板支持任意类型内存管理自动内存分配和释放迭代器支持提供随机访问迭代器STL风格接口与标准库vector类似的接口一. 主要功能模块分析1.1 核心设计思想我们的vector实现基于以下核心思想动态连续内存元素在内存中连续存储支持随机访问三指针模型通过三个指针管理内存区间指数扩容策略避免频繁内存分配RAII原则构造函数分配析构函数释放1.2 类定义框架#pragma once #includeassert.h #include initializer_list namespace wxx { templateclass 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; // 初始化列表构造C11特性 vector(std::initializer_listT il) { reserve(il.size()); for (auto e : il) { push_back(e); } } // 拷贝构造 vector(const vectorT v) { reserve(v.capacity()); // 预分配足够空间 for (auto e : v) { push_back(e); // 深拷贝每个元素 } } // 迭代器范围构造 templateclass InputIterator, typename std::enable_if!std::is_integralInputIterator::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技术应用注意迭代器范围构造函数中的特殊语法templateclass InputIterator, typename std::enable_if!std::is_integralInputIterator::value, int::type 0这是SFINAE(Substitution Failure Is Not An Error)技术的应用。其作用是当InputIterator是整数类型时模板替换失败编译器会选择vector(size_t n, T val)构造函数避免了构造函数的歧义调用四、内存管理与扩容策略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; } }关键点先分配再拷贝最后释放保证异常安全使用循环而不是memcpy确保调用正确的拷贝赋值运算符正确处理从无到有的情况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 拷贝并交换技术// 拷贝赋值运算符 vectorT operator(vectorT v) // 注意传值参数 { swap(v); // 交换当前对象和临时对象 return *this; // v离开作用域自动调用析构函数释放原资源 }6.2 swap函数实现void swap(vectorT v) { std::swap(_start, v._start); std::swap(_finish, v._finish); std::swap(_endofstorage, v._endofstorage); }特点O(1)时间复杂度不抛出异常假设std::swap不抛异常交换的是指针不是实际数据七、完整代码实现以下是完整的vector实现代码#pragma once #includeassert.h #include initializer_list #include type_traits // 需要包含这个头文件 namespace wxx { templateclass 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_listT il) { reserve(il.size()); for (auto e : il) { push_back(e); } } // 拷贝构造函数 vector(const vectorT v) { reserve(v.capacity()); for (auto e : v) { push_back(e); } } // 交换函数 void swap(vectorT v) { std::swap(_start, v._start); std::swap(_finish, v._finish); std::swap(_endofstorage, v._endofstorage); } // 赋值运算符拷贝并交换 vectorT operator(vectorT v) { swap(v); return *this; } // 迭代器范围构造函数使用SFINAE templateclass InputIterator, typename std::enable_if!std::is_integralInputIterator::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

相关文章:

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

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

Windows Terminal命令行黑科技:5个隐藏技巧让你的终端效率飙升300%

Windows Terminal命令行黑科技:5个隐藏技巧让你的终端效率飙升300% 【免费下载链接】terminal The new Windows Terminal and the original Windows console host, all in the same place! 项目地址: https://gitcode.com/GitHub_Trending/term/terminal 你是…...

基于Web的远程命令执行中心部署与安全实践指南

1. 项目概述:远程控制命令中心最近在折腾一个挺有意思的东西,一个叫cducote/remoteCC的开源项目。这个名字听起来有点抽象,但说白了,它就是一个轻量级的、基于Web的远程命令执行与控制中心。想象一下,你手头有几台服务…...

OBS多平台直播解决方案:obs-multi-rtmp技术实现与优化指南

OBS多平台直播解决方案:obs-multi-rtmp技术实现与优化指南 【免费下载链接】obs-multi-rtmp OBS複数サイト同時配信プラグイン 项目地址: https://gitcode.com/gh_mirrors/ob/obs-multi-rtmp 在当前的直播生态中,内容创作者面临着一个普遍的技术挑…...

Bard-API非官方Python接口:原理、风险与迁移官方Gemini API指南

1. 项目概述:一个非官方的Google Bard/Gemini Python接口 如果你正在寻找一个能绕过官方认证流程、直接通过浏览器Cookie与Google Bard(现已更名为Gemini)对话的Python工具,那么你很可能已经听说过或正在寻找 Bard-API 这个项目…...

Groovy高频技术问题梳理与实战开发案例解析

Groovy高频技术问题梳理与实战开发案例解析 一、概述 Groovy是基于Java虚拟机的动态脚本语言,兼容Java全部语法,兼具静态强类型与动态弱类型特性,可无缝集成Spring、Gradle、Jenkins等主流生态框架,广泛应用于后端业务开发、构建脚…...

当UWP桌面客户端重构Windows社区应用体验:桌面版酷安如何改变你的数字工作流?

当UWP桌面客户端重构Windows社区应用体验:桌面版酷安如何改变你的数字工作流? 【免费下载链接】Coolapk-UWP 一个基于 UWP 平台的第三方酷安客户端 项目地址: https://gitcode.com/gh_mirrors/co/Coolapk-UWP 在Windows系统上进行技术交流与社区互…...

NGA论坛终极美化指南:如何用开源脚本打造清爽浏览体验

NGA论坛终极美化指南:如何用开源脚本打造清爽浏览体验 【免费下载链接】NGA-BBS-Script NGA论坛增强脚本,给你完全不一样的浏览体验 项目地址: https://gitcode.com/gh_mirrors/ng/NGA-BBS-Script 还在为NGA论坛繁杂的界面而烦恼吗?想…...

终极macOS窗口自动聚焦指南:用AutoRaise提升10倍工作效率 [特殊字符]

终极macOS窗口自动聚焦指南:用AutoRaise提升10倍工作效率 🚀 【免费下载链接】AutoRaise AutoRaise (and focus) a window when hovering over it with the mouse 项目地址: https://gitcode.com/gh_mirrors/au/AutoRaise 你是否厌倦了在macOS上不…...

终极Nintendo Switch游戏安装指南:Awoo Installer如何让游戏安装变得简单快速

终极Nintendo Switch游戏安装指南:Awoo Installer如何让游戏安装变得简单快速 【免费下载链接】Awoo-Installer A No-Bullshit NSP, NSZ, XCI, and XCZ Installer for Nintendo Switch 项目地址: https://gitcode.com/gh_mirrors/aw/Awoo-Installer 还在为Sw…...

实战解析:如何用GstBuffer的Meta机制为音视频流添加自定义信息(附完整代码)

实战解析:如何用GstBuffer的Meta机制为音视频流添加自定义信息(附完整代码) 在构建现代多媒体处理流水线时,开发者经常需要在音视频帧中嵌入额外的上下文信息。想象这样一个场景:你的智能监控系统检测到画面中出现可疑…...

3步解锁「阅读」APP全功能:一站式书源配置与优化指南

3步解锁「阅读」APP全功能:一站式书源配置与优化指南 【免费下载链接】Yuedu 📚「阅读」自用书源分享 项目地址: https://gitcode.com/gh_mirrors/yu/Yuedu 还在为找不到心仪的小说资源而烦恼吗?「阅读」APP作为一款强大的小说阅读工具…...

MAA明日方舟自动化助手:5大核心功能与3步智能管理方案

MAA明日方舟自动化助手:5大核心功能与3步智能管理方案 【免费下载链接】MaaAssistantArknights 《明日方舟》小助手,全日常一键长草!| A one-click tool for the daily tasks of Arknights, supporting all clients. 项目地址: https://git…...

SpringBoot 3.x 必踩大坑:参数名丢失,全网最完整解决方案

【避坑指南】SpringBoot 3.x 必踩大坑:参数名丢失,全网最完整解决方案最近在项目从 SpringBoot 2.x 升级到 SpringBoot 3.x JDK 17 时,遇到了一大堆莫名其妙的参数报错,排查了很久才发现是 SpringBoot 3.x 编译机制改动导致的参数…...

基于EXIF与地理编码的旅行足迹地图构建实战

1. 项目概述:一个旅行足迹的智能地图管家最近在折腾一个挺有意思的小项目,叫rmartinshort/travel_mapper。简单来说,它就是一个帮你把旅行足迹,从一堆零散的照片、GPS轨迹或者手动记录的地点,自动整理并可视化到一张精…...

3个关键步骤掌握Cellpose:如何实现超越人工的细胞分割精度?

3个关键步骤掌握Cellpose:如何实现超越人工的细胞分割精度? 【免费下载链接】cellpose a generalist algorithm for cellular segmentation with human-in-the-loop capabilities 项目地址: https://gitcode.com/gh_mirrors/ce/cellpose Cellpose…...

AI应用用户调度中间件:基于MCP协议的高并发会话管理方案

1. 项目概述:一个为AI应用量身定制的用户调度中间件最近在折腾AI应用开发,特别是那些需要处理多用户并发请求、管理复杂会话状态的项目时,我总感觉缺了点什么。现有的框架要么太重,要么太轻,要么就是得自己从零开始造轮…...

用一台电脑玩多人游戏:Universal Split Screen让你和朋友共享屏幕乐趣

用一台电脑玩多人游戏:Universal Split Screen让你和朋友共享屏幕乐趣 【免费下载链接】UniversalSplitScreen Split screen multiplayer for any game with multiple keyboards, mice and controllers. 项目地址: https://gitcode.com/gh_mirrors/un/UniversalSp…...

如何在Linux上构建原生Android容器:Waydroid完整配置指南

如何在Linux上构建原生Android容器:Waydroid完整配置指南 【免费下载链接】waydroid Waydroid uses a container-based approach to boot a full Android system on a regular GNU/Linux system like Ubuntu. 项目地址: https://gitcode.com/gh_mirrors/wa/waydro…...

罗技鼠标Linux党必备:手把手教你用LogiOps在Arch系系统上实现键鼠联动(附常见错误排查)

罗技鼠标Linux党终极指南:LogiOps在Arch系系统中的高阶键鼠联动实战 在Linux桌面环境中,罗技鼠标用户常常面临一个尴尬局面:硬件性能出色,但官方驱动对Linux支持有限。对于Arch Linux或Manjaro用户而言,LogiOps的出现彻…...

终极指南:5分钟构建你的离线语音识别系统,告别云端依赖

终极指南:5分钟构建你的离线语音识别系统,告别云端依赖 【免费下载链接】whisper.cpp Port of OpenAIs Whisper model in C/C 项目地址: https://gitcode.com/GitHub_Trending/wh/whisper.cpp 在AI技术飞速发展的今天,你是否曾为语音识…...

【点米动力】现在都没几个人知道当时百度和淘宝抢电商流量入口的事情了

一个简单的robots.txt,当时可是吵到上热搜那种程度。电商发展这么多年后,都没几个人记得这些事情了。...

打通健康数据孤岛:openclaw-healthconnect-bridge部署与自动化实践

1. 项目概述与核心价值 最近在折腾个人健康数据管理时,发现了一个挺有意思的痛点:我手头有各种穿戴设备、健身App,它们产生的数据都散落在各自的“孤岛”里。比如,运动手表记录的心率、睡眠数据在厂商的App里,手动记录…...

对比直接使用原厂与通过 Taotoken 调用在配置复杂度上的差异

对比直接使用原厂与通过 Taotoken 调用在配置复杂度上的差异 对于需要集成多个大语言模型的开发者而言,管理不同厂商的 API 接入点是一项基础但繁琐的工作。每个厂商通常都有独立的注册流程、认证方式、API 端点(Base URL)和 SDK 使用规范。…...

PowerShell脚本环境探测指南

在跨平台开发和脚本执行的过程中,了解脚本运行的环境是非常关键的。尤其是当脚本需要在不同类型的shell环境中运行时,如Bash和PowerShell,脚本行为可能需要根据环境进行调整。本文将通过一个具体的实例,探讨如何在PowerShell脚本中探测调用它的shell环境,并做出相应的响应…...

AISMM模型不是方法论,是联盟生存操作系统:工信部2023-2024跨行业验证报告独家披露

更多请点击: https://intelliparadigm.com 第一章:AISMM模型不是方法论,是联盟生存操作系统:工信部2023-2024跨行业验证报告独家披露 AISMM(Alliance Intelligence & Self-Managed Matrix)并非传统意义…...

如何用KeyStore Explorer轻松管理Java密钥库?5分钟快速上手指南

如何用KeyStore Explorer轻松管理Java密钥库?5分钟快速上手指南 【免费下载链接】keystore-explorer KeyStore Explorer is a free GUI replacement for the Java command-line utilities keytool and jarsigner. 项目地址: https://gitcode.com/gh_mirrors/ke/ke…...

长期使用Taotoken服务对于项目API调用稳定性的主观感受分享

长期使用Taotoken服务对于项目API调用稳定性的主观感受分享 在持续数月的项目开发与维护过程中,我们团队将多个AI模型调用统一接入到了Taotoken平台。这篇文章旨在分享我们在此期间对服务稳定性和可用性的整体观感,侧重于实际使用中的体验,而…...

使用Node.js快速为Web应用集成多模型对话能力

使用Node.js快速为Web应用集成多模型对话能力 为Web应用添加智能对话功能,通常需要开发者处理复杂的模型API接入、密钥管理和计费问题。通过Taotoken平台提供的统一OpenAI兼容API,开发者可以简化这一过程,快速集成多种主流大模型&#xff0c…...

MultiDIC:多视角三维视觉测量与实验力学分析的开源创新工具

MultiDIC:多视角三维视觉测量与实验力学分析的开源创新工具 【免费下载链接】MultiDIC Matlab 3D Digital Image Correlation Toolbox 项目地址: https://gitcode.com/gh_mirrors/mu/MultiDIC MultiDIC作为一款专业的MATLAB工具箱,为三维视觉测量…...