当前位置:网站首页>vector的基本实现
vector的基本实现
2022-07-31 23:36:00 【华华的bit】
Vector
vector模拟实现
memcpy对reserve影响
关于Vector的介绍具体的请查看该网站(https://m.cplusplus.com/reference/vector/vector/)
1️⃣
- 基本框架
-
构造、析构、运算符、迭代器、容量、运算符
构造函数
1.默认构造函数:空容器构造
vector()
:_start(nullptr)
,_finish(nullptr)
,_endofstoage(nullptr)
{
}
2.填充构造:n个元素的容器,每个元素都是val的副本
vector(size_t n, const T& val = T())
:_start(nullptr)
, _finish(nullptr)
, _endofstoage(nullptr)
{
reserve(n);
for (size_t i = 0; i < n; ++i)
{
push_back(val);
}
}
3.范围构造函数:构造一个容器,其元素数与范围 [first,last) 相同,每个元素都按相同的顺序从该区域中的相应元素构造
template<class InputIterator>
vector(InputIterator first, InputIterator last)
: _start(nullptr)
, _finish(nullptr)
, _endofstoage(nullptr)
{
while (first!=last)
{
push_back(*first);
++first;
}
}
析构函数
将销毁所有容器元素,并使用其分配器释放矢量分配的所有存储容量
~vector()
{
if (_start)
{
delete[] _start;
_start = _finish = _endofstoage = nullptr;
}
}
运算符=
将新内容分配给容器,替换其当前内容,并相应地修改其大小
vector<T>& operator=(vector<T> v)
{
swap(v);
return *this;
}
这里swap采用的是该函数
void swap( vector& v)
{
std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_endofstoage, v._endofstoage);
}
迭代器
1.begin
指向序列容器开头的迭代器。
返回指向向量中第一个元素的迭代器。
iterator begin()
{
return _start;
}
const_iterator begin() const
{
return _start;
}
这边我使用了2种一种是可读的有const一种是可读可写的无const。
2.end
序列末尾后元素的迭代器。
返回一个迭代器,该迭代器引用矢量容器中的末日后元素。
iterator end()
{
return _finish;
}
const_iterator end() const
{
return _finish;
}
这边我使用了2种一种是可读的有const一种是可读可写的无const。
容量
1.size
容器中的元素数。
返回矢量中的元素数。
size_t size() const
{
return _finish - _start;
}
2.capacity
返回当前为向量分配的存储空间的大小。
size_t capacity() const
{
return _endofstoage - _start;
}
3.resize
调整容器大小,使其包含 n 个元素。
如果 n 小于当前容器大小,则内容将减少到其前 n 个元素,删除超出(并销毁)的元素。
如果 n 大于当前容器大小,则通过在末尾插入所需数量的元素以达到 n 的大小来扩展内容。如果指定了 val,则新元素将初始化为 val 的副本,否则,它们将进行值初始化。
如果 n 也大于当前容器容量,则会自动重新分配分配的存储空间。
void resize(size_t n,T val=T())
{
if (n > capacity())
{
reserve(n);
}
if (n > size())
{
while (_finish < _start + n)
{
*_finish=val;
++_finish;//不理解
}
}
else
{
_finish=_start+n;
}
}
4.reserve
请求向量容量至少足以包含 n 个元素。
如果 n 大于当前矢量容量,则该函数会导致容器重新分配其存储,将其容量增加到 n(或更大)。但不会进行初始化。这点和resize不同。
void reserve(size_t n)
{
size_t sz = size();
if (n > capacity())
{
T* tmp = new T[n];
if (_start)
{
//memcpy(tmp, _start, size() * sizeof(T));
for (size_t i = 0; i < size(); ++i)
{
tmp[i]=_start[i];
}
delete[] _start;
}
_start = tmp;
}
_finish = _start + sz;
_endofstoage = _start + n;
}
5.运算符[]
访问元素:返回对矢量容器中位置 n 处的元素的引用。
T& operator[](size_t pos)
{
assert(pos < size());
return _start[pos];
}
const T& operator[](size_t pos) const
{
assert(pos < size());
return _start[pos];
}
- 增加功能
-
增加增删查改等
1.swap
通过 x 的内容交换容器的内容,x 是同一类型的另一个向量对象。
void swap( vector<T>& v)
{
std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_endofstoage, v._endofstoage);
}
2.push_back
在矢量的末尾,在其当前的最后一个元素之后添加一个新元素。val 的内容被复制(或移动)到新元素。
void push_back(const T& x)
{
/* if (_finish == _endofstoage) { size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2; reserve(_endofstoage); } *_finish = x; ++_finish;*/
insert(end(),x);
}
3.pop_back
删除矢量中最后一个元素并且容器减少一给。
void pop_back()
{
/*if (_finish > _start) { --_finish; }*/
erase(end() - 1);
}
4.insert插入
通过在元素之前的指定位置插入新元素.将容器大小增加插入的元素数。
iterator insert(iterator pos, const T& x)
{
assert(pos >= _start && pos <= _finish);
if (_finish == _endofstoage)
{
size_t n = pos - _start;
size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;
reserve(newCapacity);
pos = _start + n;
}
iterator end = _finish - 1;
while (end >= pos)
{
*(end + 1) = *end;
--end;
}
*pos = x;
++_finish;
return pos;
}
5.erase擦除
从向量中删除单个元素(位置)或一系列元素([first,last))。
返回时指向函数调用擦除的最后一个元素后面的元素的新位置的迭代器。如果操作擦除了序列中的最后一个元素,则这是容器结束。
iterator erase(iterator pos)
{
assert(pos >= _start && pos < _finish);
iterator it = pos + 1;
while (it != _finish)
{
*(it - 1) = *it;
++it;
}
--_finish;
return pos;
}
6.clear
从矢量中删除所有元素\使容器的大小为 0。
void clear()
{
_finish=_start;
}
2️⃣
memcpy对reserve影响
memcpy将一段内存空间中内容原封不动的拷贝到另外一段内存空间中。但如果拷贝的是自定义类型元素,并且
自定义类型元素中涉及到资源管理时,就会出错,因为memcpy的拷贝实际是浅拷贝。我们通过实际进行验证。
通过图我们可以发现问题,指向的地址一样,指向的空间释放。产生了随机值。因此我们在使用的时候产生了野指针。我们如果要处理这个问题。可以选择通过新空间来存放,在释放原有空间。这样问题就处理了。
以上是我对vector的理解,可能有所不足。
边栏推荐
- 新产品如何进行网络推广?
- Payment module implementation
- 消息队列消息存储设计(架构实战营 模块八作业)
- 字符编码和浮点型计算精度丢失问题
- vim的基本使用-命令模式
- 什么是动态规划,什么是背包问题
- hboot and recovery, boot.img, system.img
- [QNX Hypervisor 2.2用户手册]9.16 system
- The difference between adding or not adding the ref keyword when a variable of reference type is used as a parameter in a method call in C#
- Flutter教程之 02 Flutter 桌面程序开发入门教程运行hello world (教程含源码)
猜你喜欢
ICML2022 | 深入研究置换敏感的图神经网络
cobaltstrike
Shell common scripts: Nexus batch upload local warehouse enhanced version script (strongly recommended)
基于单片机GSM的防火防盗系统的设计
C# Rectangle基本用法和图片切割
Unity-LineRenderer显示一条线
A high-quality WordPress download site template theme developed abroad
(26) About menu of the top menu of Blender source code analysis
日常--Kali开启SSH(详细教程)
[Reading Notes -> Data Analysis] 02 Data Analysis Preparation
随机推荐
SQL injection Less47 (error injection) and Less49 (time blind injection)
Daily--Kali opens SSH (detailed tutorial)
推荐系统:常用评价指标总结【准确率、精确率、召回率、命中率、(归一化折损累计增益)NDCG、平均倒数排名(MRR)、ROC曲线、AUC(ROC曲线下的面积)、P-R曲线、A/B测试】
Difference Between Stateless and Stateful
UOS - WindTerm use
IPD流程专业术语
Learn about C# anonymous methods
lua入门案例实战1234定义函数与标准函数库功能
#yyds dry goods inventory# Interview must brush TOP101: the entry node of the ring in the linked list
Dry goods | 10 tips for MySQL add, delete, change query performance optimization
基于mysql的消息队列设计
Binary tree non-recursive traversal
基于RT1052 Aworks nanopb string 类型固定长度使用方式(二十七)
Flutter教程之 02 Flutter 桌面程序开发入门教程运行hello world (教程含源码)
SQL注入 Less42(POST型堆叠注入)
Program processes and threads (concurrency and parallelism of threads) and basic creation and use of threads
Unity - LineRenderer show a line
NIO编程
[QNX Hypervisor 2.2 User Manual]9.14 set
Unity-LineRenderer显示一条线