(C++) 简单实现vector

news/2024/2/28 1:00:49

文章目录

  • 前言
  • Code
    • LH_Mouse 的基础版本
    • 简单改良
  • END

前言

对于自己尝试写的一些模仿标准库等操作。永远不要觉得自己实现的有多nb,在各大编译器的标准库面前就是个弟弟。

因此别再觉得自己数据结构课上写的那些基础线性表操作有多熟料,只能说人外有人,山外有山。

对于实现一个vector的基本考虑

  • 数据类型的声明
  • 构造 constructor
  • 析构 destructor
  • 拷贝 移动 copy move
  • 迭代器 iterators
  • 存取器 accessor
  • 容量 capacity
  • 修改器 modifier
  • 尾部追加删除 do_back
  • 运算符重载
  • 等等等等

Code

本文参考 LH_Mouse 的简单vector的实现,作为笔记和交作业。

LH_Mouse 的基础版本

手写一个 std::vector 可以有多复杂?_哔哩哔哩_bilibili

这只是在短时间内能考虑到的简单版本~

#include <stddef.h>#include <iostream>
#include <string>namespace my {
template <class ValueT>
class vector {
public:using value_type = ValueT;using reference = ValueT&;using const_reference = const ValueT&;using iterator = ValueT*;using const_iterator = const ValueT*;using size_type = ::size_t;// 迭代器相减using difference_type = ::ptrdiff_t;private:ValueT* m_data;::size_t m_size;::size_t m_capacity;public:// 默认无参构造constexpr vector() noexcept : m_data(), m_size(), m_capacity() {}// 内存是vector自己管理的// 只想销毁对象~vector() {this->clear();::operator delete(this->m_data);}// 拷贝构造vector(const vector& rhs) {// 注意 operator new 会抛出异常this->m_data = static_cast<ValueT*>(::operator new(rhs.m_capacity * sizeof(ValueT)));this->m_size = 0;this->m_capacity = rhs.m_capacity;try {for (::size_t k = 0; k < rhs->m_size; k += 1) {// placement new// new时考虑异常::new (&this->m_data[k]) ValueT(rhs.m_data[k]);this->m_size += 1;}} catch (...) {for (::size_t k = 0; k < this->m_size; k += 1) {this->m_data[k].~ValueT();}::operator delete(this->m_data);// 将异常重新抛出throw;}}// 移动构造vector(vector&& rhs) {this->m_data = rhs.m_data;this->m_size = rhs.m_size;this->m_capacity = rhs.m_capacity;rhs.m_data = nullptr;rhs.m_size = 0;rhs.m_capacity = 0;}vector& operator=(const vector& rhs) {return *this;}vector& operator=(vector&& rhs) {return *this;}public:  // 涉及到指针的,需要考虑const版本// iteratorsiterator begin() noexcept {return this->m_data;}const_iterator begin() const noexcept {return this->m_data;}iterator end() {return this->m_data + this->m_size;}const_iterator end() const {return this->m_data + this->m_size;}// accessorvalue_type* data() noexcept {return this->data;}const value_type* data() const noexcept {return this->m_data;}size_type size() const noexcept {return this->m_size;}size_type capacity() const noexcept {return this->m_capacity;}bool empty() const noexcept {return this->m_size == 0;}// modifiervoid clear() noexcept {for (::size_t k = 0; k < this->m_size; k += 1) {this->m_data[k].~ValueT();}this->m_size = 0;}void pop_back() noexcept {// 保证size>0assert(!this->empty());::size_t k = this->m_size - 1;this->m_data[k].~ValueT();this->m_size += -1;}void push_back(const ValueT& value) {this->emplace_back(value);}void push_back(ValueT&& value) {this->emplace_back(::std::move(value));}template <typename... Args>reference emplace_back(Args&&... args) {if (this->m_size < this->m_capacity) {// `data` can not be null::size_t k = this->m_size;::new (&this->m_data[k]) ValueT(::std::forward<Args>(args)...);this->m_size += 1;return this->m_data[k];}// 此时 size == capacity// 扩容1.5倍::size_t new_capacity = this->m_size + 1;new_capacity |= this->m_size / 2;::size_t new_size = 0;auto new_data =static_cast<ValueT*>(::operator new(new_capacity * sizeof(ValueT)));try {for (::size_t k = 0; k < this->m_size; k += 1) {// placement new// new时考虑异常::new (&new_data[k]) ValueT(::std::move(this->m_data[k]));new_size += 1;}::new (&new_data[new_size]) ValueT(::std::forward<Args>(args)...);new_size += 1;} catch (...) {for (::size_t k = 0; k < new_size; k += 1) {new_data[k].~ValueT();}::operator delete(new_data);// 将异常重新抛出throw;}// 将原数据析构this->clear();::operator delete(this->m_data);this->m_data = new_data;this->m_size = new_size;this->m_capacity = new_capacity;return new_data[new_size];}
};
}  // namespace myint main() {::my::vector<::std::string> vec;vec.push_back("hello");vec.emplace_back();vec.emplace_back("hello", 4);// 标准不禁止// vec.emplace_back(vec[0]);for (const auto& str : vec) {::std::cout << str << ::std::endl;}return 0;
}

简单改良

真的,楼主感觉喵喵写已经非常优良和精简了。个人也只是做了简单的补充和注释。

比如补了一下赋值操作,简单封装了析构的功能函数等。


注意这里还是有很多情况没有考虑,以个人能力非要考虑的话也只能写出效率极低,冗余度高的丑陋代码

  • 如果考虑以迭代器为参数构造
    • 只能访问一次的迭代器该如何处理
  • 扩容时候插入的元素为原序列本身的元素
    • 扩容时移动到新空间错误
  • 部分new操作没考虑异常
  • 等等等等
#include <stddef.h>#include <iostream>
#include <string>namespace my {
template <class ValueT>
class vector {
public:using value_type = ValueT;using reference = ValueT&;using const_reference = const ValueT&;using iterator = ValueT*;using const_iterator = const ValueT*;using size_type = ::size_t;// 迭代器相减using difference_type = ::ptrdiff_t;private:ValueT* m_data;::size_t m_size;::size_t m_capacity;public:// 默认无参构造constexpr vector() noexcept : m_data(), m_size(), m_capacity() {}// 内存是vector自己管理的// 只想销毁对象~vector() {this->destruct_this();}// 拷贝构造vector(const vector& rhs) {// 注意 operator new 会抛出异常this->m_data = static_cast<ValueT*>(::operator new(rhs.m_capacity * sizeof(ValueT)));this->m_size = 0;this->m_capacity = rhs.m_capacity;try {for (::size_t k = 0; k < rhs->m_size; k += 1) {// new时考虑异常::new (&this->m_data[k]) ValueT(rhs.m_data[k]);this->m_size += 1;}} catch (...) {destruct_this();throw;}}// 移动构造vector(vector&& rhs) {this->m_data = rhs.m_data;this->m_size = rhs.m_size;this->m_capacity = rhs.m_capacity;rhs.m_data = nullptr;rhs.m_size = 0;rhs.m_capacity = 0;}// 偷懒的写法vector& operator=(const vector& rhs) {auto tmp = rhs;using ::std::swap;swap(tmp, *this);return *this;}vector& operator=(vector&& rhs) {auto tmp = ::std::move(rhs);using ::std::swap;swap(tmp, *this);return *this;}public:  // 涉及到指针的,需要考虑const版本// iteratorsiterator begin() noexcept {return this->m_data;}const_iterator begin() const noexcept {return this->m_data;}iterator end() {return this->m_data + this->m_size;}const_iterator end() const {return this->m_data + this->m_size;}// accessorvalue_type* data() noexcept {return this->data;}const value_type* data() const noexcept {return this->m_data;}size_type size() const noexcept {return this->m_size;}size_type capacity() const noexcept {return this->m_capacity;}bool empty() const noexcept {return this->m_size == 0;}// modifiervoid clear() noexcept {destruct_len(this->m_data, this->m_size);this->m_size = 0;}void pop_back() noexcept {// 保证size>0assert(!this->empty());::size_t k = this->m_size - 1;this->m_data[k].~ValueT();this->m_size += -1;}// 调用 emplace_backvoid push_back(const ValueT& value) {this->emplace_back(value);}void push_back(ValueT&& value) {this->emplace_back(::std::move(value));}// 注意要使用完美转发template <typename... Args>reference emplace_back(Args&&... args) {if (this->m_size < this->m_capacity) {::size_t k = this->m_size;::new (&this->m_data[k]) ValueT(::std::forward<Args>(args)...);this->m_size += 1;return this->m_data[k];}// 此时 size == capacity// 扩容1.5倍::size_t new_capacity = this->m_size + 1;new_capacity += this->m_size / 2;::size_t new_size = 0;auto new_data =static_cast<ValueT*>(::operator new(new_capacity * sizeof(ValueT)));try {for (::size_t k = 0; k < this->m_size; k += 1) {// 并不是所有情况下的移动都是合理的::new (&new_data[k]) ValueT(::std::move(this->m_data[k]));new_size += 1;}::new (&new_data[new_size]) ValueT(::std::forward<Args>(args)...);new_size += 1;} catch (...) {destruct_len(new_data, new_size);::operator delete(new_data);// 将异常重新抛出throw;}// 将原数据析构// 如果上面抛出异常了,这里可能把原数据全清了this->destruct_this();// 接管所有权this->m_data = new_data;this->m_size = new_size;this->m_capacity = new_capacity;return new_data[new_size];}private:// 其实是析构的一个抽象void destruct_this() noexcept {this->clear();::operator delete(this->m_data);}void destruct_len(ValueT* pdata, ::size_t len) noexcept {for (::size_t k = 0; k < len; k += 1) {pdata[k].~ValueT();}}
};
}  // namespace myint main() {::my::vector<::std::string> vec;vec.push_back("hello");vec.emplace_back();vec.emplace_back("hello", 4);// 标准不禁止// vec.emplace_back(vec[0]);for (const auto& str : vec) {::std::cout << str << ::std::endl;}return 0;
}



END


http://www.ppmy.cn/news/577723.html

相关文章

C语言二级指针

文章目录 1 什么是二级指针2 二级指针代码实现参考 1 什么是二级指针 如果一个指针指向的是另外一个指针&#xff0c;我们就称它为二级指针&#xff0c;或者指向指针的指针。 假设有一个 int 类型的变量 a&#xff0c;p1是指向 a 的指针变量&#xff0c;p2 又是指向 p1 的指针…

【SD卡修复】使用SDFormatter工具

转载自&#xff1a;[Windows] sd卡救卡神器SDFormatter–亲测有效 工具使用 安装链接&#xff1a;SDFormatter 如果不打算要数据的话&#xff0c;直接点击格式化就可以了 这软件是用来格式化sd卡的。会清除数据的&#xff01;&#xff01;&#xff01;&#xff01;看清图…

LeetCode 双周赛 107(2023/06/24)滑动窗口与离散化

本文已收录到 AndroidFamily&#xff0c;技术和职场问题&#xff0c;请关注公众号 [彭旭锐] 和 [BaguTree Pro] 知识星球提问。 往期回顾&#xff1a;LeetCode 单周赛第 348 场 数位 DP 模版学会了吗&#xff1f; T1. 最大字符串配对数目&#xff08;Easy&#xff09; 标签&…

SD卡受损怎么修复

进入dos&#xff0c;找到开始菜单&#xff0c;在运行框中输入cmd后回车。 执行chkdsk I:/F(I是SD卡盘符&#xff0c;F是修复参数&#xff09;。 等待修复完成&#xff0c;DOS窗口会自动关闭。 把TF卡插入读卡器&#xff0c;接到电脑USB后&#xff0c;电脑提示格式化&#xf…

SD卡修复

SD卡插到电脑上&#xff0c;打开时提示IO 错误&#xff0c;而在手机上就显示SD出问题&#xff0c;需要格式化SD卡&#xff0c;放到电脑上压根就打不开SD卡了&#xff0c;右键也提示IO错误&#xff0c;在同事的提示下&#xff0c;说可以通过dos的命令来修复&#xff0c;尝试了一…

sd卡图片损坏怎么修复?

在旅途中&#xff0c;正常情况下用相机拍的照片都是存在相机的SD卡里的。等到我们需要时&#xff0c;在进行导出。但如果是出现意外导致sd卡图片遭到损坏&#xff0c;遇到这种情况&#xff0c;sd卡图片损坏怎么修复呢?这里小编将为大家分享一些图片修复技巧。操作很简单。相信…

SD卡受损无法识别,如何在Windows 10/8/7下修复?

文章来源&#xff1a;https://www.reneelab.com.cn/repair-sd-card-windows.html 目录 一、SD卡插入Windows电脑后&#xff0c;提示“使用驱动器中的光盘前需要将其格式化”状况分析解决方案 二&#xff0e;Windows10/8/7对插入的SD卡完全没有反应状况分析解决方法 三&#xff…

linux sd卡修复工具,免费的SD卡数据恢复工具介绍

都叫兽™ 数据恢复-简单强大的数据恢复软件 多种恢复方式可针对不同情况选择文件恢复、格式化恢复、分区恢复、创建镜像功能 操作简单只需几步就能恢复数据&#xff0c;新手也能快速上手 可恢复各种文件类型 办公文件、图文、视频、音频、压缩文件等类型。 支持多种设备除了支持…

修复SD卡

坑爹的手机....反应不了我的操作....然后自动重启&#xff0c;导致SD卡受损.... 经过两小时的抢救&#xff0c;终于抢救成功。案发现场.... 1.重启后.... 2.发现状况不对....马上连上电脑....还是不行....于是拿了舍友的读卡器....插进SD卡....连上电脑.....还是发现不能读取…

SD卡损坏了怎么办?sd卡恢复,80%的用户都试过这些方法

SD卡作为一种外部存储设备&#xff0c;多用在数据相机、监控、手机、无人机等设备中&#xff0c;可以帮我们保存很多数据。 但是SD卡也跟其他设备一样&#xff0c;容易发生数据丢失的情况。如果SD卡损坏了&#xff0c;或者我们把里面的数据误删或者格式化&#xff0c;sd卡恢复…

SD卡损坏及手动修复记录

文章目录 前言背景SD卡参数损坏过程损坏后效果 修复过程一、寻找错误点1. 打开WinHex2. 打开磁盘3. 打开正常的SD卡4. 查找分区表位置 二、修复错误1. 复制移位的引导扇区2. 把移位的引导扇区粘贴到正确位置 三、修复结果 结语附录相关大佬文章及学习链接 前言 本文将讲述我的…

如何修复损坏的SD卡并找回数据

可以不格式化修复损坏的SD卡错误吗&#xff1f; 「早上当我试着用Facebook在我的手机上分享一些照片时&#xff0c;出现了一则SD卡错误信息&#xff0c;显示『SD卡已损坏&#xff0c;请尝试重新格式化』。当我按下按钮后Android提醒我&#xff1a;『确定要将SD卡格式化吗&…

SD卡受损最简单的修复方法,太神奇了

如何修复受损的SD卡?很多的数据存储设备在使用时间过长之后都容易出现损坏等的意外,这样会导致一些数据出现乱码、丢失、损坏等的情况,严重影响到了用户的使用,那么各位是否知道如何修复受损的SD卡呢?丢失的数据又该怎么恢复呢?  要修复损坏的SD卡的话,可以像修复U盘一…

sd卡受损修复办法

以后出现SD卡受损&#xff0c;千万不要再格式化内存卡了。 修复过程: 1、手机提示TF卡受损&#xff0c;需要格式化 。 2、把TF卡插入读卡器&#xff0c;接到电脑USB后&#xff0c;电脑提示格式化&#xff0c;点取消。然后查看一下属性。 直接使用属性中的 工具-开始检查。发现无…

SD卡内存卡修复工具哪个好?4款工具对比测评

现在的内存卡不管是SD卡还是 TF卡还是手机内存卡都或多或少有各种各样的问题&#xff0c;内存卡又不像U盘可以用 量产工具修复&#xff0c;如果出现无法格式化&#xff0c;不能读出数据&#xff0c;不能打开等问题受伤的不止是数据还有内存卡本身也没法使用&#xff0c;大多数…

小米笔记本 - 驱动下载

首页 / 帮助中心 / 小米笔记本及周边产品 / 驱动下载 1. 输笔记本编号 搜索到结果 点击游戏本名字&#xff0c;就可以进入驱动下载页面了。 选择驱动 点击所需驱动&#xff0c;下载即可。数度比驱动精灵&#xff0c;驱动大师之类的爽多了。

android win10 驱动安装失败,解决在win10系统下小米手机驱动安装失败的具体步骤...

随着系统的升级越来越快&#xff0c;对于许多用户的系统都已经升级到win10系统了&#xff0c;win10系统在给用户带来方便的同时&#xff0c;有时候也会遇到一些小麻烦&#xff0c;比如说对于最新的Window10正式版系统而言&#xff0c;基本主流的手机驱动都能自动检测安装。不过…

小米随身wifi驱动linux驱动下载,小米随身WIFI驱动|小米WIFI驱动官方最新版(支持Win10)...

小米随身wifi驱动是小米随身WiFi的驱动程序。只要安装好小米随身wifi驱动官方版&#xff0c;插入小米随身wifi&#xff0c;就能创建免费WiFi网络&#xff0c;让你的手机和平板立刻连上WiFi&#xff0c;再也不用担心你的流量&#xff01; 软件特色 可同时接入多个设备&#xff0…

Ubuntu 下小米手机驱动

默认情况下 Ubuntu系统无法识别android手机。 运行 adb devices 将会出现一堆 &#xff1f;&#xff1f;&#xff1f;号 在这种情况下你可以按照如下方法解决 1.首先查看你手机的ID号 在terminal下运行lsusb命令 再将手机连接上电脑 再次运行lsusb就会多出一个usb信息。该信息即…

win7下如何安装小米手机驱动

许多新手在刷机的时候苦苦不会装驱动&#xff0c;下面本猫来教新手。老鸟勿喷 1.使用数据线连接手机和电脑&#xff0c;会出现如下提示 2.点击桌面我的电脑&#xff0c;右击属性 3.双击位置设备 4.点击浏览我的电脑安装驱动 5.选择我的电脑里面的那个下载下来的驱动位置 6.点击…
最新文章