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

CD43.vector模拟实现(2)

目录

1.拷贝构造函数

写法1

写法2

测试代码

调试找bug

解决方法:修改拷贝构造函数

测试代码

2.operator[ ]

测试代码

1.没有const修饰

2.有const修饰

3.insert

迭代器失效问题


承接CD42.vector模拟实现(1)文章

1.拷贝构造函数

设置start、finish和end_of_storage这几个参数就行,注意是深拷贝!

写法1

vector(const vector<value_type>& x):start(0), finish(0), end_of_storage(0)
{start = new T[x.capacity()];memmove(start, x.start, x.size()*sizeof(value_type));finish = start + x.size();end_of_storage = start + x.capacity();
}

注:new的参数可以为capacity,也可以为size,这个C++标准没有规定,空间可以不一样,但是有效元素必须一样

写法2

复用reserve和memmove函数

这个代码有问题:

vector(const vector<value_type>& x):start(0), finish(0), end_of_storage(0)
{reserve(x.capacity());memmove(start, x.start, x.size() * sizeof(value_type));
}

测试代码

void const_vector_print(const mystl::vector<int> v)
{for (size_t i = 0;i < v.size(); i++)std::cout << v[i] << " ";
}void test6()
{mystl::vector<int> v;v.push_back(1); v.push_back(2);v.push_back(3); const_vector_print(v);return;
}

运行结果:什么都没有打印

调试找bug

什么都没有打印,可以判定没有进入循环,

下断点到循环,看看情况:

start和finish的地址一样,v.size()计算出来为0,没有进入循环,可以断定拷贝构造函数出了问题,

下断点到拷贝构造函数,再次调试:

x.capacity()计算出来是4,进入reserve函数内部:

对空的vector进行reserve,看以下分析图:

解决方法:修改拷贝构造函数

reserve没有更新finish,那就手动更新finish

vector(const vector<value_type>& x):start(0), finish(0), end_of_storage(0)
{reserve(x.capacity());finish = start + x.size();memmove(start, x.start, x.size() * sizeof(value_type));
}

而且标准库也是这样实现的:

运行结果:

同理,reserve函数也要修改:

void  reserve(size_type n)
{if (n > capacity()){T* tmp = new T[n];size_t len = size();//delete前先保存元素的个数!bool flag = false;if (size() == 0){flag = true;len = n;}memmove(tmp,start , size()* sizeof(value_type));delete[] start;if (flag)//如果vector在什么元素都没有{start = finish = tmp;}else{start = tmp;finish = start + len;}end_of_storage = start + n;}
}

测试代码

void test4()
{mystl::vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);mystl::vector<int> v2(v1);for (auto& a:v2)std::cout << a << " ";
}

运行结果:

2.operator[ ]

参数保持一样的类型:

注意到返回类型被重定义过,因此先进行重定义:

typedef value_type& reference;
typedef const value_type& const_reference;

必须保证提供的n是合法的,换句话说,n<size(),可以使用assert断言

reference operator[] (size_type n)
{assert(n < size());return *(start + n);//也可以写成start[n]
}const_reference operator[] (size_type n) const
{assert(n < size());return *(start + n);//也可以写成start[n]
}

测试代码

1.没有const修饰

void test5()
{mystl::vector<int> v;v.push_back(1); v[0]++;v.push_back(2); v[1]++;v.push_back(3); v[2]++;for (auto& a : v)std::cout << a << std::endl;return;
}

运行结果:

2.有const修饰

void const_vector_print(const mystl::vector<int> v)
{for (size_t i = 0;i < v.size(); i++)std::cout << v[i] << " ";
}void test6()
{mystl::vector<int> v;v.push_back(1); v.push_back(2);v.push_back(3); const_vector_print(v);return;
}

运行结果:

3.insert

参数保持一样的类型,为了简单起见,这里只实现第一个

首先要断言,position必须合法:

assert(position >= start && position <= finish);

插入前先看看是否需要扩容,可以直接借用CD42.vector模拟实现(1)文章的push_back函数的代码:

if (finish == nullptr)reserve(4);
if (finish == end_of_storage)reserve(capacity() * 2);

和CD38.【C++ Dev】string类的模拟实现(2)文章类似的思路,先移动再插入

迭代器失效问题

如果insert的返回值是void,

void insert(iterator position, const value_type& val)
{assert(position >= start && position <= finish);if(finish == nullptr)reserve(4);if (finish == end_of_storage)reserve(capacity() * 2);iterator i = finish-1;while (i >= position){*(i+1) = *i;i--;}*position = val;finish++;
}

头插:

void test7()
{mystl::vector<int> v;v.push_back(1);v.push_back(2);v.insert(v.begin(), 3);return;
}

 

尾插:

void test7()
{mystl::vector<int> v;v.push_back(1);v.push_back(2);v.insert(v.end(), 3);return;
}

中间位置插入:

void test7()
{mystl::vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.insert(v.begin() + 1, 4);return;
}

貌似没有问题,但是如果是这个测试代码:

void test7()
{mystl::vector<int> v;v.push_back(1);auto pos = v.begin();for (size_t i = 2; i <= 8; i++)v.insert(pos, i);return;
}

运行结果会出问题: 

引出迭代器失效问题

pos记录的是原来v的start的值,如果v扩容,start的值会改变,但pos的值没有更新,而且原先的内存空间被释放会导致非法访问,因此再执行v.insert(pos, i);就会出问题(即pos为野指针)

解决方法:扩容后更新pos的值,STL的解决方法:返回值为iterator

 

iterator insert(iterator position, const value_type& val)
{assert(position >= start && position <= finish);if(finish == nullptr)reserve(4);if (finish == end_of_storage)reserve(capacity() * 2);iterator i = finish-1;while (i >= position){*(i+1) = *i;i--;}*position = val;finish++;return start;
}

注:position不能引用传参,有可能insert的第一个参数会做算术运算,例如:
 

v.insert(pos+20, i);

测试代码: 

void test7()
{mystl::vector<int> v;v.push_back(1);auto pos = v.begin();for (size_t i = 2; i <= 8; i++)pos=v.insert(pos, i);return;
}

验证pos是否更新:
原先:

扩容更新后:

运行结果:退出代码为0

当然CD42.vector模拟实现(1)文章的push_back可以复用insert的代码

1.如果不接收insert的返回值,扩容要慎重,修改可能会报错,因为不一定扩容,所以不一定失效;

2.insert以后就不要使用原本定义的迭代器

http://www.xdnf.cn/news/12230.html

相关文章:

  • 守护生命律动:进行性核上性麻痹的专业健康护理指南
  • Docker快速部署AnythingLLM全攻略
  • CSS选择子元素
  • mysql数据库的导入导出专题
  • SpringBoot parent依赖高版本覆盖低版本问题
  • 《小明的一站式套餐服务平台》
  • Go内存模型基础:理解内存分配机制
  • 从OCR到Document Parsing,AI时代的非结构化数据处理发生了什么改变?
  • OpenProject:一款功能全面的开源项目管理软件
  • 2.0 阅读方法论与知识总结
  • grafana 批量视图备份及恢复(含数据源)
  • 【拓扑】1639.拓扑排序
  • python版若依框架开发:python版若依部署
  • 【系统架构设计师】绪论-系统架构概述
  • Cisco Packet Tracer软件如何修改文件存储位置
  • 【计算机组成原理 第5版】白、戴编著 第三章多层次的存储器 题型总结2 cache部分
  • Java异步编程难题拆解技术
  • LVS、NGINX、HAPROXY的调度算法
  • Spring Cloud 深度解析:构建高可用微服务架构实践指南
  • 文本内容变化引起布局尺寸变化 导致的 UI 适配问题
  • 工业软件低代码开发平台技术架构研究
  • SQL语法
  • ROS 2 环境下使用 Astra Pro 深度相机实现目标距离检测及远程可视化全流程总结
  • 制作一款打飞机游戏65:时间表修正
  • AirSim/Cosys-AirSim 游戏开发(一)XBox 手柄 Windows + python 连接与读取
  • 估计二维结构的数量
  • 尝试使用gocryptfs实现大模型加密部署
  • AI书签管理工具开发全记录(十):命令行中结合ai高效添加书签
  • Vue指令修饰符、v-bind对样式控制的增强、computed计算属性、watch监视器
  • 【c++】STL-string容器的使用