各位好友, 本期 ------>Vector(容器)----->深浅拷贝 开战 !
----->代码如下 :>
------>头文件 “Vector.h” :>
//Vector(容器)模拟实现
namespace UC
{
template<class 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()
{}
vector(size_t n, const T& val= T())
{
resize(n, val);
}
//拷贝构造 ---->第一种写法
vector(const T& v)
{
_start = new T[v.capacity()];
//此处涉及到 浅拷贝, 会使得程序发生崩溃 !
//memcpy(_start, v._start, sizeof(T) * v.size());
//正确拷贝 赋值行为
for(size_t i = 0; i < v.size(); i++)
{
_start[i] = v._start[i];
}
_finish = _start + v.size();
_endofstorge = _start + v.capacity();
}
//拷贝构造 ---->第二种写法
vector(const T& v)
{
reserve(v.capacity());
for(auto e : v)
{
v.push_back(e);
}
}
//多参数构造 ---->难点理解
vector(size_t n, const T& val = T())
{
resize(n, val);
}
vector(int n, const T& val = T())
{
resize(n, val);
}
template<class InputIterator> //模板内可以再套用一个模板
vector(InputIterator first, InputIterator last)
{
while(first != last)
{
push_back(*first);
++first;
}
}
//扩容
void reserve(size_t n)
{
if(n > capacity())
{
size_t sz = size(); //注意 :>此处需要保存数值---->难点
T* tamp = new T[n];
if(_start)
{
//此处涉及到 浅拷贝, 致使程序运行会发生错误
///memcpy(tamp, _start, sizeof(T) * sz);
//正确拷贝赋值行为
for(size_t i = 0; i < size(); i++)
{
tamp[i] = _start[i];
}
delete[] _start;
}
_start = tamp;
_finish = _start + sz;
_endofstoarge = _start + n;
}
}
//追加数据
void push_back(const T& x)
{
insert(end(), x);
}
//插入数据
iterator insert(iterator pos, const T& val)
{
assert(pos >= _start && pos <= _finish);
if(_finish == _endofstorge)
{
size_t len = pos - _start;
size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;
reserve(newCapacity);
pos = len + _start;
}
iterator end = _finish - 1;
while(end >= pos)
{
*(end + 1) = *end;
--end;
}
*pos = val;
++_finish;
return pos;
}
void resize(size_t n, const T& val = T())
{
if(n < size())
{
_finish = _start + n;
}
else
{
while(_finish != _start + n)
{
*_finish = val;
++_finish;
}
}
}
size_t size() const
{
return _finish - _start;
}
size_t capacity() const
{
return _endofstorge - _start;
}
T& operator[](iterator pos)
{
assert(pos < size());
return _start[pos];
}
const T& operator[](iterator pos)
{
assert(pos < size());
return _start[pos];
}
~vector()
{
delete[] _start;
_start = _finish = _endofstorge = nullptr;
}
private:
iterator _start = nullptr;
iterator _finish = nullptr;
iterator _endofstorge = nullptr;
}
}
----->测试环节 “Test.cpp” :>
//测试运行一组 ---->隐藏Bug
#include "Vector.h"
void test_01()
{
UC :: vector<string> v1;
v1.push_back("111111111111");
v1.push_back("222222222222");
v1.push_back("333333333333");
for(auto e : v1)
{
cout << e << " ";
}
cout << endl;
}
void test_02()
{
UC :: vector<string> v1;
v1.push_back("111111111111");
v1.push_back("222222222222");
v1.push_back("333333333333");
v1.push_back("101010101010");
v1.push_back("010101010101");
for(auto= e : v1)
{
cout << e << " ";
}
cout << endl;
}
int man()
{
test_0();
return 0;
}
为了方便好友们, 有更好地观感体验, 现附上 彩色代码图样 :>
深拷贝 ------->致使拷贝赋值函数不足性 :>
深拷贝 ---------->致使扩容函数不足性 :>
------>测试 一 :>
------>测试 二 :>
------->针对上述情况, 做如下说明 :>
上述程序, 三个值的运行, 是可以拷贝成功 !但是 增加到 五个值的时候, 就会发生程序崩溃 !
------->原因 :> 隐藏的 深拷贝, 主要发生在扩容环节 !请看下列图示 :>
在 VS 2019 编译器下 存储 vector<string>对象
如果 该对象大小是在 16 字节之内 则会存储 在系统上提前开辟的一个 buff[16] 数组
------>如果 该对象大小 大于了 16字节
则编译器 会额外开辟一个新空间 来存储该对象 !而提前开辟好的空间就会浪费掉 !
另外补充一点 :>内置类型 深拷贝, 无须改动上述原先代码 !
---------------------------->因为 内置类型 深拷贝 又叫做 值拷贝 !
即 memcpy()函数对于内置类型没有任何问题, 但 对于自定义类型 就会发生崩溃现象 !
现对 memcpy()函数 深入 探究 !如下 :>
注意 :>T 作 自定义类型 时
-------->会依次调用数组内 每个对象的析构函数, 之后再调用 delete[]函数 -->销毁空间
-------->其中, tamp 没有发生 浅拷贝; 但是 tamp 内部对象 发生了 浅拷贝 !
即:>vector 是 深拷贝, 但是 vector 空间上 存在的对象 是 string 对象;
----------------------------->使用 memcpy()函数 导致 string 对象发生了 浅拷贝 !
经过 delete[]之后, 新空间内 拷贝没问题, 空间大小 也没问题
--------------->但是 string 对象 内部指针 --------->会变成 野指针 !
各位好友, 本期专栏 内容 已快要完结 !下面再扩展一个 vector ()函数 构造场景 !如下 :>
-------------------------->注意 :>新构造 vector 函数 ---->模板类型 是一致的 !(关键点)
测试 环节 一 :>
------>解决方案 :>
由此可见, 程序编译不通过 ! 具体原因 :>测试环节, 实参部分 前后类型不一致 !
----------->
至此, 本模块, vector (容器)模拟实现 ----->已完成 !
下一期, 终于 要向 List (链表)进行宣战了 ! “敬请期待 !😊😊