目录
1.介绍
2.模拟实现
2.1.基本框架
2.2.简单函数实现
2.3.扩容函数实现
2.4插入删除函数实现
2.5构造函数等
2.6迭代器失效问题
举例:
void test_vector1()
{
vector v;
v.push_back(7);
v.push_back(3);
v.push_back(5);
v.push_back(9);
v.push_back(2);
for (auto& ch : v)
{
ch += 1;
cout << ch << " ";
}
cout << endl;
vector::iterator it = v.begin();
while (it != v.end())
{
(*it) -= 1;
cout << *it << " ";
it++;
}
cout << endl;
sort(v.begin(), v. end());
for (auto ch : v)
{
cout << ch << " ";
}
cout << endl;
}
结果:
8 4 6 10 3
7 3 5 9 2
2 3 5 7 9
int main()
{
vector v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
v.push_back(6);
vector::iterator it = v.begin();
while (it != v.end())
{
if (*it % 2 == 0)
{
it = v.insert(it, 20);//insert返回的是新插入元素的后一个元素的地址
it++;
}
it++;
}
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
return 0;
}
结果:
1 20 2 3 20 4 5 20 6
用法与string类似,可查看文档:vector - C++ Reference 进行学习。
namespace LF
{
template
class vector
{
public:
typedef T* iterator;
typedef const T* const_iterator;
vector()//无参构造函数
:_start(nullptr)
, _finish(nullptr)
, _endofstoage(nullptr)
{}
//........其余函数的实现
private:
iterator _start;//T类型的指针,指向该内存空间起始位置
iterator _finish;//指向有效数据的位置
iterator _endofstoage;//指向该内存结束位置
};
}
iterator begin()//返回起始空间的地址
{
return _start;
}
iterator end()
{
return _finish;
}
const_iterator begin() const
{
return _start;
}
const_iterator end() const
{
return _finish;
}
size_t size() const//返回元素的个数
{
return _finish - _start;
}
size_t capacity() const//返回容量的大小
{
return _endofstoage - _start;
}
T& operator[](size_t pos)
{
assert(pos < size());
return _start[pos];
}
const T& operator[](size_t pos) const
{
assert(pos < size());
return _start[pos];
}
void clear()
{
_finish = _start;
}
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];//若—_start[i]是vector类型,里面有指针,要完成深拷贝
}
delete[] _start;
}
_start = tmp;//_start所指向的空间改变了
}
_finish = _start + sz;//扩容后—_start改变了,—_finish应在新的_start后面
_endofstoage = _start + n;
}
void resize(size_t n, T val = T())//T()会去调用它的默认构造函数,在C++中,内置类型也有默认构造函数
{
if (n > capacity())
{
reserve(n);
}
if (n > size())
{
while (_finish < _start + n)
{
*_finish = val;
++_finish;
}
}
else
{
_finish = _start + n;
}
}
void push_back(const T& x)
{
if (_finish == _endofstoage)
{
size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;
reserve(newCapacity);
}
*_finish = x;
++_finish;
}
void pop_back()
{
if (_finish > _start)
{
--_finish;
}
}
iterator insert(iterator pos , const T&)//此处pos接受的是值传递
{
assert(pos >= _start && pos <= _finish);
size_t sz = pos - _start;
if (_finish == _endofstoage)
{
size_t newcapacity = capacity() == 0 ? 4 : capacity() * 4;
reverse(newcapacity);
pos = _start + sz;//扩容后,pos指向的内存空间也失效了,要重新赋值
}
// 2 4 6 7
iterator end = _finish - 1;
while (end>=pos)
{
*(end + 1) = *end;
end--;
}
*pos = x;
++_finish;
return pos;//返回的pos指针是指向新元素的
}
iterator erase(iterator pos)
{
assert(pos >= _start && pos < _finish);
iterator it = pos + 1;
while (it != _finish)
{
*(it - 1) = *it;
++it;
}
--_finish;
return pos;
}
template
vector(InputIterator first, InputIterator last)
: _start(nullptr)
, _finish(nullptr)
, _endofstoage(nullptr)
{
while (first != last)
{
push_back(*first);
++first;
}
}
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);
}
}
vector(int n, const T& val = T())
: _start(nullptr)
, _finish(nullptr)
, _endofstoage(nullptr)
{
reserve(n);
for (int i = 0; i < n; ++i)
{
push_back(val);
}
}
void swap(vector& v)
{
std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_endofstoage, v._endofstoage);
}
vector(const vector& v)
: _start(nullptr)
, _finish(nullptr)
, _endofstoage(nullptr)
{
vector tmp(v.begin(), v.end());//构造一个临时对象,开辟新空间,内容与v相同
swap(tmp);//将*this与tmp中的三个指针交换。
}
vector& operator=(vector v)//值传递
{
swap(v);
return *this;
}
iterator insert(iterator pos , const T&)//此处pos接受的是值传递
{
assert(pos >= _start && pos <= _finish);
size_t sz = pos - _start;
if (_finish == _endofstoage)
{
size_t newcapacity = capacity() == 0 ? 4 : capacity() * 4;
reverse(newcapacity);
pos = _start + sz;//扩容后,pos指向的内存空间也失效了,要重新赋值
}
// 2 4 6 7
iterator end = _finish - 1;
while (end>=pos)
{
*(end + 1) = *end;
end--;
}
*pos = x;
++_finish;
return pos;//返回的pos是指向新元素的
}
库里面的实现与上面原理类似,每次插入新元素后,返回的是新元素的地址。
倘若在没有接受该函数的返回值的情况下:
1.若未发生扩容,此时的pos指针指向新插入的数据。
2.若发生扩容,由于该函数中pos是值传递,即使在函数内部改变了pos,在未接受返回值的情况下,该pos所指向的内存空间已经失效了。
在vs2022下演示:
int main()
{
vector v;
v.reserve(10);
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(5);
v.push_back(6);
auto pos = find(v.begin(), v.end(), 5);
if (pos!=v.end())
{
cout << "capacity:"<
在未扩容的情况下,pos所指向的空间不变,但数据改变了,在vs2022平台上不能进行访问(vs2014可以访问);
在扩容的情况下,pos所指向的空间已失效。vextor
iterator erase(iterator pos)
{
assert(pos >= _start && pos < _finish);
iterator it = pos + 1;
while (it != _finish)
{
*(it - 1) = *it;
++it;
}
--_finish;
return pos;//返回的pos指向的数据是被删除元素的下一个元素
}
因为erase函数删除数据时,不会减小容量,不会存在野指针问题,但pos指向的数据意义变了(与insert中第二种情况一样)。vs2022下不可访问,可认为失效了。
不同平台下检查机制不一样,可能有不同的结果,
总结:在使用insert,erase函数时,最好要接受它的返回值。