前言
本期带来vector实现,和以前的顺序表差别不大。
博主水平有限,不足之处望请斧正!
预备知识
实现参考SGI
的stl30
我们看这种源码,要抓框架看:首先找类,看它的属性,再看方法
template <class T, class Alloc = alloc>
class vector {
public:
typedef T value_type;
typedef value_type* iterator;
typedef const value_type* const_iterator;
//...
protected:
iterator start;
iterator finish;
iterator end_of_storage;
//...
}
public:
iterator begin() { return start; }
const_iterator begin() const { return start; }
iterator end() { return finish; }
const_iterator end() const { return finish; }
//...
}
可以看到,vector
是使用三个迭代器 start
、 finish
、 end_of_storage
维护的,这是怎么个思路?
如图所示:
_start
指向起始位置_finish
指向最后一个有效数据的下一个位置_endofstorage
指向容量的下一个位置
有了这些储备,就能开始实现我们自己的vector了。
实现
分离
我们用一个 main.cpp
和一个 vector.h
#include <iostream>
using namespace std;
#include "vector.h"
int main()
{
bacon::...; //调用测试函数
return 0;
}
这里需要注意命名空间展开和包含头文件的顺序:为了编译速度,编译器找定义都是向上找。当 "vector.h"
展开,只会向上找——如果先包含 "vector.h"
后展开命名空间,"vector.h"
中使用 cout
之类向上就找不到。
跑起来
namespace bacon
{
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()
:_start(nullptr)
,_finish(nullptr)
,_endofstorage(nullptr)
{}
size_t capacity() { return _endofstorage - _start; }
size_t size() { return _finish - _start; }
void reserve(size_t n)
{
if(n > capacity())
{
size_t oldsize = size();
T* tmp = new T[n];
if(_start)
{
memcpy(tmp, _start, sizeof(T) * size());
}
delete[] _start;
_start = tmp;
_finish = _start + size();
_endofstorage = _start + size();
}
}
void push_back(const T& val)
{
if(_finish == _endofstorage)
reserve(capacity() == 0 ? 4 : capacity() * 2);
*_finish = val;
++_finish;
}
T& operator[](size_t index)
{
assert(index < size());
return _start[index];
}
private:
iterator _start;
iterator _finish;
iterator _endofstorage;
};
void test1()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
for(size_t i = 0; i < v.size(); ++i)
{
cout << v[i] << ' ';
}
cout << endl;
}
}
//main.cpp
#include <iostream>
using namespace std;
#include "vector.h"
int main()
{
bacon::test1();
return 0;
}
测一下发现报错了
注意:reserve
这里非常容易出bug
void reserve(size_t n)
{
if(n > capacity())
{
T* tmp = new T[n];
if(_start)
{
memcpy(tmp, _start, sizeof(T) * size());
}
delete[] _start;
_start = tmp;
//size():return _finish - _start
//_finish = _start + _finish - _start;
_finish = _start + size();
_endofstorage = _start + size();
}
}
size()
本来应该用老的_start
来和_finish
作差,但是_start
变了,导致size()返回的不是0,而是_finish - _start
,原语句则变成_finish = _start + _finish - _start;
最终_finish
还是nullptr
。
解决方案1:先更新_finish
,仍然能用老的_start
计算大小。
_finish = tmp + size();
_start = tmp;
_endofstorage = _start + size();
解决方案2:提前保存size,用临时保存的size迭代_finish
和_endofstorage
。
size_t oldsize = size();
_start = tmp;
_finish = _start + oldsize;
_endofstorage = _start + oldsize;
所以reserve
应该是这样:
void reserve(size_t n)
{
if(n > capacity())
{
size_t oldsize = size();
T* tmp = new T[n];
if(_start)
{
memcpy(tmp, _start, sizeof(T) * size());
}
delete[] _start;
//err:_start的改变影响size()
//_finish = _start + size() = _start + _finish - _start = nullptr
//1.调换顺序
_finish = tmp + size();
_start = tmp;
_endofstorage = _start + size();
//2.提前保存
_start = tmp;
_finish = _start + oldsize;
_endofstorage = _start + n;
}
}
跑起来:
//vector.h
void test1()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
for(size_t i = 0; i < v.size(); ++i)
{
cout << v[i] << ' ';
}
cout << endl;
}
//main.cpp
#include <iostream>
using namespace std;
#include "vector.h"
int main()
{
bacon::test1();
return 0;
}
1 2 3 4 1 2 3 4
补充成员函数
resize
、empty
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;
}
}
bool empty() { return _start == _finish; }
resize
-
需要扩容则扩容
-
n > size:填数据
-
n <= size:删除数据
(n == size)包含在哪种情况都一样
跑一下:
void test2()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
for(size_t i = 0; i < v.size(); ++i)
{
cout << v[i] << ' ';
}
cout << endl;
v.resize(100);
cout << v.size() << endl;
cout << v.capacity() << endl;
for(size_t i = 0; i < v.size(); ++i)
{
cout << v[i] << ' ';
}
cout << endl;
}
//main.c
#include <iostream>
using namespace std;
#include "vector.h"
int main()
{
bacon::test2();
return 0;
}
1 2 3 4 1 2 3 4
100
8
1 2 3 4 1 2 3 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
pop_back
void pop_back()
{
assert(!empty());
--_finish;
}
insert
void insert(iterator pos, const T& val)
{
if(_finish == _endofstorage)
reserve(capacity() == 0 ? 4 : capacity() * 2);
iterator end = _finish - 1; //最后一个有效数据
while(end >= pos)
{
*(end + 1) = *end;
--end;
}
*pos = val;
++_finish;
}
测一下,发现报错。
因为属性换成 _start
这些,挪动数据的时候不会有类型提升影响。那是什么问题?
其实是迭代器是小问题
#在insert内部,迭代器失效
为什么?
未扩容前:
pos仍正常,属于_start
到 _finish
的范围内
扩容后:
画图分析一下:
扩容导致_start
和 _finish
变化,所以pos已经不属于 _start
到 _finish
的范围内了。此时,用 end
和 pos
比较显然不是我们的意思了。
所以如果扩容了,需要更新一下 pos
(按理也要检查一下pos)。
所以insert内部迭代器失效的原因是:扩容,未更新迭代器。
怎么解决?
更新迭代器
void insert(iterator pos, const T& val)
{
assert(pos >= _start && 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 = val;
++_finish;
}
:
更新成功。
void test4()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
for(size_t i = 0; i < v.size(); ++i)
{
cout << v[i] << ' ';
}
cout << endl;
v.insert(v.begin(), 9);
for(size_t i = 0; i < v.size(); ++i)
{
cout << v[i] << ' ';
}
cout << endl;
}
1 2 3 4
9 1 2 3 4
insert内部迭代器失效
原因:扩容,迭代器未更新,导致迭代器野指针。
解决:更新迭代器。
#在insert外部,迭代器失效
void test4()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
for(size_t i = 0; i < v.size(); ++i)
{
cout << v[i] << ' ';
}
cout << endl;
vector<int>::iterator pos = find(v.begin(), v.end(), 2);
v.insert(pos, 9);
for(size_t i = 0; i < v.size(); ++i)
{
cout << v[i] << ' ';
}
*(pos)++; //可以吗?
cout << endl;
}
main
内 insert
以后,pos
能否继续使用?
不能,有可能是失效的。insert
内的迭代器是传值传参得到的,不影响main内的 pos
,而我们仅在 insert
内 更新了迭代器,若 insert
时发生扩容,main
的 pos
不会被更新。
那有什么方式可以解决?
传值不行,传引用?还是不行。引用形参只能接收左值(能修改的),当我们传了右值,如 v.begin()
,调用返回涉及到临时变量,就会出错。
Error:非常量引用的初始值必须为左值
看看文档,发现还有个返回值
iterator insert (iterator position, const value_type& val);
文档中这样描述返回值:
An iterator pointing to the new location of the element that followed the last element erased by the function call. This is the container end if the operation erased the last element in the sequence.
一个迭代器,指向被函数调用删除的最后一个元素之后的元素的新位置。如果操作擦除了序列中的最后一个元素,则这是容器结束。
比如,某迭代器原来指向 v[3]
,删除后指向新的 v[3]
,如果 v[3]
是最后一个元素,迭代器就是_finish
。
哦!当我们 insert
后还是需要用 pos
,通过返回值更新一下就好了!
iterator insert(iterator pos, const T& val)
{
assert(pos >= _start && 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 = val;
++_finish;
return pos;
}
insert外部迭代器失效
原因:insert的迭代器参数是传值传参,内部更新不影响外部。main的迭代器仍然失效。
解决:外部按需通过返回值更新迭代器。
erase
经历前面的迭代器失效后,我们也想:这个会不会也导致迭代器失效呢?
好像不会哦?因为不缩容,空间不会变的。用库里的测一下,看库怎么说:
void test5()
{
std::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
std::vector<int>::iterator pos = find(v.begin(), v.end(), 3);
v.erase(pos);
for (size_t i = 0; i < v.size(); ++i)
{
cout << v[i] << ' ';
}
cout << endl;
//读
cout << *pos << endl;
//写
++(*pos);
}
vs2022:
Xcode:
1 2 4
4
#在erase外部,迭代器失效
为什么?
- 意义来说,迭代器如果不更新,是失效的(原来指向的数据都删了,现在指向谁说不准)
- 而且我们的代码得在所有平台能跑。
所以我们还是认为 erase
后,迭代器失效。
怎么解决?
同样的,通过返回值来选择性更新(需要再用就更新)。
iterator erase(iterator pos)
{
assert(!empty());
assert(pos >= _start && pos < _finish);
iterator begin = pos + 1;
while(begin < _finish)
{
*(begin - 1) = *begin;
++begin;
}
--_finish;
return pos;
}
erase外部迭代器失效
原因:意义改变
解决:按需通过返回值更新迭代器
find
可以直接用算法库的find
了
template<class InputIterator, class T>
InputIterator find (InputIterator first, InputIterator last, const T& val)
{
while (first!=last) {
if (*first==val) return first;
++first;
}
return last;
}
算法库的find
是函数模版,只需要我们的vector
支持 !=
、 *
、 ==
、 ++
就行。
void test4()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
for(size_t i = 0; i < v.size(); ++i)
{
cout << v[i] << ' ';
}
cout << endl;
vector<int>::iterator pos = find(v.begin(), v.end(), 2);
if(pos != v.end())
v.insert(pos, 9);
for(size_t i = 0; i < v.size(); ++i)
{
cout << v[i] << ' ';
}
cout << endl;
}
1 2 3 4
1 9 2 3 4
swap
void swap(vector<T>& v)
{
std::swap(this->_start, v._start);
std::swap(this->_finish, v._finish);
std::swap(this->_endofstorage, v._endofstorage);
}
clear
void clear() { _finish = _start; }
~vector
~vector()
{
delete[] _start;
_start = _finish = _endofstorage = nullptr;
}
vector(const vector<T>& v)
传统写法:开空间,拷贝数据(复用)
vector(const vector<T>& v)
:_start(nullptr)
,_finish(nullptr)
,_endofstorage(nullptr)
{
reserve(v.capacity());
for(auto& e : v) //不加引用每次拿v内对象赋值给e,效率低
{
push_back(e);
}
}
现代写法:抓壮丁(迭代器区间构造)
vector(InputIterator first, InputIterator last)
template <class InputIterator>
vector(InputIterator first, InputIterator last)
:_start(nullptr)
,_finish(nullptr)
,_endofstorage(nullptr)
{
while(first != last)
{
push_back(*first);
++first;
}
}
vector(const vector<T>& v)
:_start(nullptr)
,_finish(nullptr)
,_endofstorage(nullptr)
{
vector<T> man(v.begin(), v.end());
swap(man);
}
vector<T>& operator= (vector<T>& v)
现代写法:抓壮丁(传值传参调用拷贝构造产生的临时对象)
vector<T>& operator= (vector<T> v)
{
swap(v);
return *this;
}
只要拷贝构造写好了,都能用这个现代写法~
但是,上面的写法有一个缺陷:v1 = v1
,自己给自己赋值,白拷贝了。但可以容忍,因为这种场景非常少,而且程序能正常运行。
想实现全一点的话还可以实现一个这个。
explicit vector (size_type n, const value_type& val = value_type()
explicit
:由于这是个单参构造,涉及赋值运算符的时候,若类型合适,可能将 n
转换为 vector
。
class t1
{
public:
t1(int n) :_n(n) {}
private:
int _n;
};
class t2
{
public:
explicit t2(int n) :_n(n) {}
private:
int _n;
};
int main()
{
int num = 0;
t1 t1 = num;
t2 t2 = num;
return 0;
}
如上,单参构造类型合适(int的形参和要初始化的属性合适),int n
转换成了t1 n
。
如此能防止单参构造的 n
转换为 vector
。
explicit vector(size_t n, const T& val = T())
:_start(nullptr)
,_finish(nullptr)
,_endofstorage(nullptr)
{
reserve(n);
for(int i = 0; i < n; ++i)
{
push_back(val);
}
}
但是,这有个坑。
#n个val构造
的匹配问题
void test9()
{
//vector<char> v(10, 'A'); //正常运行
vector<int> v(10, 1);
for(auto e : v)
cout << e << ' ';
cout << endl;
}
vector<int> v(10, 1);
vector(size_t n, const T& val = T())
template <class InputIterator>
vector(InputIterator first, InputIterator last)
为什么vector<char> v(10, 'A');
能匹配到vector(size_t n, const T& val = T())
?
10
这个字面量的类型是int
,'A'
这个字面量的类型是char
,模版参数T
上绑定了char
类型。虽然int
到size_t
有一点不匹配,但是可以类型转换,也没有其他更加匹配的函数。
而对于vector<int> v(10, 1);
,两个字面量类型都是int
,调用vector(size_t n, const T& val = T())
需要将int
转换为size_t
,函数模版显然能产生更好的匹配,int被当做迭代器解引用,当然不行。
那如何解决呢?
想不到办法可以参考源码的实现
vector() : start(0), finish(0), end_of_storage(0) {}
vector(size_type n, const T& value) { fill_init ialize(n, value); }
vector(int n, const T& value) { fill_initialize(n, value); }
vector(long n, const T& value) { fill_initialize(n, value); }
explicit vector(size_type n) { fill_initialize(n, T()); }
直接一样来一个。
explicit vector(int n, const T& val = T())
:_start(nullptr)
,_finish(nullptr)
,_endofstorage(nullptr)
{
reserve(n);
for(int i = 0; i < n; ++i)
{
push_back(val);
}
}
explicit vector(size_t n, const T& val = T())
:_start(nullptr)
,_finish(nullptr)
,_endofstorage(nullptr)
{
reserve(n);
for(int i = 0; i < n; ++i)
{
push_back(val);
}
}
原因:迭代器区间模版更匹配
解决:一样来一个,让它匹配
到这就差不多了……吗?
我们开空间的操作还有问题!拷数据简单地用memcpy
就能解决吗?不能!当要拷贝的元素涉及深拷贝就完了!
#元素浅拷贝问题
void test11()
{
vector<int> v(10, 1);
vector<vector<int>> vv;
vv.push_back(v);
for(size_t i = 0; i < vv.size(); ++i)
{
for(size_t j = 0; j < vv[i].size(); ++j)
{
cout << vv[i][j] << ' ';
}
cout << endl;
}
cout << endl;
}
void reserve(size_t n)
{
if(n > capacity())
{
size_t oldsize = size();
T* tmp = new T[n];
if(_start)
{
// 浅拷贝不够用,有些要深拷贝的
memcpy(tmp, _start, sizeof(T) * size());
}
delete[] _start;
_start = tmp;
_finish = _start + oldsize;
_endofstorage = _start + n;
}
}
对于reserve画图分析一下:
这是浅拷贝后未释放空间的情况,vv
的属性直接拷贝给tmp
,vv
和 tmp
指向同一块空间。这时再 delete[] _start;
,对每个自定义类型vector<int> v
都调用析构,在这之前,每个vector<int> v
又会对自己的空间调用析构。
扩容后,vv
指向新空间,但新空间的前4个元素的空间已经被析构,此时如果vv[0][0]
,解引用野指针,必然出错。
调试验证:
1.浅拷贝,新空间指向原空间
2.原空间释放,新空间受影响,[_start, _start+4) 变成野指针
3.解引用野指针(对野指针的访问,打印出随机值)
为什么说C++不适合用C语言的内存函数,这里若用realloc,其内部memcpy拷贝数据,完球。(要使用必须确定不会影响)
对于哪哪都是自定义类型的C++,我们尽量选择为其量身定制的new 和 delete,会自动调用构造和析构。
如何解决?自然是每个元素都深拷贝:
void reserve(size_t n)
{
if(n > capacity())
{
size_t oldsize = size();
T* tmp = new T[n];
if(_start)
{
// 浅拷贝不够用,有些要深拷贝的
// memcpy(tmp, _start, sizeof(T) * size());
for(size_t i = 0; i < oldsize; ++i)
{
tmp[i] = _start[i];
}
}
delete[] _start;
_start = tmp;
_finish = _start + oldsize;
_endofstorage = _start + n;
}
}
解决是解决了,效率是不是有点低?确实,现阶段没有好的解决办法,后期学了C++11就有了。
此处的问题不仅出现在刚刚的场景,只要是涉及 reserve
拷贝数据的地方,都会出现问题,如 拷贝构造
,其中调用了 push_back
,会调用到 reserve
。
vector
的实现到这就差不多了,附上整体代码(如有错误不足之处,希望指出)
namespace bacon
{
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()
:_start(nullptr)
,_finish(nullptr)
,_endofstorage(nullptr)
{}
//explicit:对于单参的构造,类型合适的时候会触发隐式类型转换
//这里是怕n隐式类型转换成vector,传size_t就不会转换成vector
explicit vector(int n, const T& val = T())
:_start(nullptr)
,_finish(nullptr)
,_endofstorage(nullptr)
{
reserve(n);
for(int i = 0; i < n; ++i)
{
push_back(val);
}
}
//按n的类型再给一个(long也能再给一个)方法,解决参数不匹配的问题
explicit vector(size_t n, const T& val = T())
:_start(nullptr)
,_finish(nullptr)
,_endofstorage(nullptr)
{
reserve(n);
for(int i = 0; i < n; ++i)
{
push_back(val);
}
}
template <class InputIterator>
vector(InputIterator first, InputIterator last)
:_start(nullptr)
,_finish(nullptr)
,_endofstorage(nullptr)
//这里的实现体现了迭代器的意义,不同的迭代器,同样的控制,一套代码走所有容器
{
while(first != last)
{
push_back(*first);
++first;
}
}
//现代写法
vector(const vector<T>& v)
:_start(nullptr)
,_finish(nullptr)
,_endofstorage(nullptr)
{
vector<T> man(v.begin(), v.end());
swap(man);
}
//复用写法
// vector(const vector<T>& v)
// :_start(nullptr)
// ,_finish(nullptr)
// ,_endofstorage(nullptr)
// {
// reserve(v.capacity());
// for(auto& e : v) //不加引用每次拿v内对象赋值给e,效率低
// {
// push_back(e);
// }
// }
~vector()
{
delete[] _start;
_start = _finish = _endofstorage = nullptr;
}
//v1 = v1
vector<T>& operator= (vector<T> v)
{
swap(v);
return *this;
}
bool empty() const { return _start == _finish; }
size_t capacity() const { return _endofstorage - _start; }
size_t size() const { return _finish - _start; }
void reserve(size_t n)
{
if(n > capacity())
{
size_t oldsize = size();
T* tmp = new T[n];
if(_start)
{
// 浅拷贝不够用,有些要深拷贝的
// memcpy(tmp, _start, sizeof(T) * size());
for(size_t i = 0; i < oldsize; ++i)
{
tmp[i] = _start[i];
}
}
delete[] _start;
//err:_start的改变影响size()
//_finish = _start + size() = _start + _finish - _start = nullptr
//1.调换顺序
// _finish = tmp + size();
// _start = tmp;
// _endofstorage = _start + size();
//2.提前保存
_start = tmp;
_finish = _start + oldsize;
_endofstorage = _start + n;
}
}
void resize(size_t n, T val = T())
{
// 1. 需要扩容则扩容
// 2. n > size:填数据
// 3. n <= size:删除数据
// (n == size)包含在哪种情况都一样
if(n > capacity()) reserve(n); //需要扩就扩了
if(n > size())
{
while(_finish < _start + n)
{
*_finish = val;
++_finish;
}
}
else
{
_finish = _start + n;
}
}
void push_back(const T& val)
{
if(_finish == _endofstorage)
reserve(capacity() == 0 ? 4 : capacity() * 2);
*_finish = val;
++_finish;
}
void pop_back()
{
assert(!empty());
--_finish;
}
iterator insert(iterator pos, const T& val)
{
assert(pos >= _start && 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 = val;
++_finish;
return pos;
}
iterator erase(iterator pos)
{
assert(!empty());
assert(pos >= _start && pos < _finish);
iterator begin = pos + 1;
while(begin < _finish)
{
*(begin - 1) = *begin;
++begin;
}
--_finish;
return pos;
}
void swap(vector<T>& v)
{
std::swap(this->_start, v._start);
std::swap(this->_finish, v._finish);
std::swap(this->_endofstorage, v._endofstorage);
}
void clear() { _finish = _start; }
T& operator[](size_t index)
{
assert(index < size());
return _start[index];
}
const T& operator[](size_t index) const
{
assert(index < size());
return _start[index];
}
private:
iterator _start;
iterator _finish;
iterator _endofstorage;
};
}
重点回顾
insert内部的迭代器失效
- 原因:扩容,迭代器未更新,野指针
- 解决:需要扩容则更新迭代器
insert外部的迭代器失效
- 原因:insert迭代器传值传参,内部更新不影响外部
- 解决:按需用返回值更新迭代器
erase外部的迭代器失效
- 原因:迭代器指向的数据已经删除,迭代器意义改变
- 解决:按需用返回值更新迭代器
n个val构造类型不匹配
- 原因:有些场景类型不够匹配,会走到迭代器区间构造(模版)
- 解决:按n可能传的类型,多写几个这样的构造
元素浅拷贝问题
- 原因:对自定义类型的元素浅拷贝,指向错误,导致新空间被影响
- 解决:对每个元素的拷贝都调用它们自己的赋值重载或者拷贝构造等。
今天的分享就告一段落了。
这里是培根的blog,期待与你共同进步!
下期见~