目录
vector的模拟实现源代码:
#pragma once
#include<iostream>
#include<vector>
#include<assert.h>
using namespace std;
namespace kl
{
template<class T>
class vector
{
public:
typedef T* iterator;
typedef const T* const_iterator;
//默认构造函数
vector()
:_start(nullptr)
, _finish(nullptr)
, _end_of_storage(nullptr)
{
}
vector(size_t n, const T& value = T())
:_start(new T[n])
, _finish(_start + n)
, _end_of_storage(_start + n)
{
for (int i = 0; i < n; i++)
{
_start[i] = value;
}
}
vector(int n, const T& value = T())
:_start(new T[n])
, _finish(_start + n)
, _end_of_storage(_start + n)
{
for (int i = 0; i < n; i++)
{
_start[i] = value;
}
}
template<typename Inputiterator>
vector(Inputiterator first, Inputiterator finish)
{
T* _tmp = new T[finish - first];
_start = _tmp;
while (first != finish)
{
*_tmp = *first;
first++; _tmp++;
}
_finish = _end_of_storage = _tmp;
}
//拷贝构造 传统写法
vector(const vector<T>& v)
:_start(nullptr)
,_finish(nullptr)
,_end_of_storage(nullptr)
{
_start = new T[v.capacity()];
const_iterator it = v.begin();
T* tmp = _start;
//memcpy(_start, v._start, sizeof(T) * v.size());
while (it != v.end())
{
*_start = *it;
_start++, it++;
}
_start = tmp;
_finish = _start + v.size();
_end_of_storage = _start + v.capacity();
}
~vector()
{
if (_start)
{
delete[] _start;
_start = _finish = _end_of_storage = nullptr;
}
}
//赋值重载现代写法
vector<T>& operator=(vector<T> v)
{
swap(v);
return *this;
}
iterator begin()
{
return _start;
}
iterator end()
{
return _finish;
}
const_iterator begin()const //const T* const this
{
return _start;
}
const_iterator end()const
{
return _finish;
}
int size()const
{
return _finish - _start;
}
int capacity()const
{
return _end_of_storage - _start;
}
bool empty()const
{
return _start == _finish;
}
void reserve(size_t n)
{
if (capacity() < n)
{//开始扩容
int _size = size();
T* _tmp = new T[n];
//把原来的数据拷贝到新开辟的空间
memcpy(_tmp, _start, sizeof(T) * capacity());
_start = _tmp;
_finish = _start + _size;
_end_of_storage = _start + n;
}
}
void resize(size_t n,const T& value = T())
{
if (n < capacity())
{//小于的话就缩容
_finish = _start + n;
}
else
{//开始扩容
int _size = size();
T* _tmp = new T[n];
//把原来的数据拷贝到新开辟的空间
memcpy(_tmp, _start, sizeof(T) * capacity());
_start = _tmp;
_finish = _start + _size;
_end_of_storage = _start + n;
//把方面的值附上初始值,改变size的值
while (_finish < _end_of_storage)
{
*_finish++ = value;
}
}
}
//vector的增删查改
void push_back(const T& value)
{
if (size() == capacity())
{//扩容
size_t _capacity = capacity() == 0 ? 1 : int(capacity() * 2);
reserve(_capacity);
}
*_finish++ = value;
}
void pop_back()
{
erase(_finish - 1);
}
iterator insert(iterator position, const T& value)
{
assert(position <= _start || position >= _end_of_storage);
//首先判断是否要扩容
if (size() + 1 > capacity())
{
size_t _capacity = capacity() == 0 ? 1 : int(capacity() * 2);
reserve(_capacity);
}
iterator end = _finish - 1;
while (end >= position)
{
*(end + 1) = *end;
end--;
}
*position = value;
//更新长度
_finish++;
return position;
}
iterator erase(iterator position)
{
assert(position <= _start || position >= _end_of_storage);
auto end = position + 1;
while (end <= _finish)
{
*(end - 1) = *(end);
end++;
}
//更新长度
_finish--;
return end;
}
void swap(vector<T>& x)
{
std::swap(_start,x._start);
std::swap(_finish, x._finish);
std::swap(_end_of_storage, x._end_of_storage);
}
T& operator[](size_t n)
{
return _start[n];
}
const T& operator[](size_t n)const
{
return _start[n];
}
private:
T* _start;
T* _finish;
T* _end_of_storage;
};
}
测试代码:
#include"MyVector.h"
void test01()
{
/*vector<int> v(10, 1);
cout << "size: " << v.size() << endl;
cout<<"capacity: " << v.capacity() << endl;
for (auto e : v)
{
cout << e << " ";
}
cout << endl;*/
//kl::vector<int> v1(10, 1);
/*cout << "size: " << v1.size() << endl;
cout << "capacity: " << v1.capacity() << endl;
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
kl::vector<int> v2(v1);
for (auto e : v2)
{
cout << e << " ";
}
cout << endl;*/
}
void TestVectorExpandOP()
{
vector<int> v;
size_t sz = v.capacity();
v.reserve(10); // 提前将容量设置好,可以避免一遍插入一遍扩容
cout << "making bar grow:\n";
for (int i = 0; i < 10; ++i)
{
v.push_back(i);
if (sz != v.capacity())
{
sz = v.capacity();
cout << "capacity changed: " << sz << '\n';
}
}
v.reserve(30);
}
void test02()
{
TestVectorExpandOP();
}
void test03()
{
/*vector<int> v(10, 1);
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
v.resize(5);
cout << v.capacity() << endl;
cout << v.size() << endl;
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
kl::vector<int> v1(10, 1);
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
v1.resize(20);
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;*/
}
void test04()
{
//vector<int> v;
//v.push_back(1);
//v.push_back(2);
//v.push_back(3);
//v.push_back(4);
//v.push_back(5);
//auto it = find(v.begin(),v.end(),2);
//v.insert(it, 100);
//v.pop_back();
//v.pop_back();
//v.pop_back();
//v.pop_back();
//v.pop_back();
//v.pop_back();
v.pop_back();
//for (auto e : v)
//{
// cout << e << " ";
//}
//cout << endl;
/*kl::vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(5);
auto it1 = find(v1.begin(), v1.end(), 2);
v1.insert(it1, 100);
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
v1.pop_back();
v1.pop_back();
v1.pop_back();
v1.pop_back();
v1.pop_back();
v1.pop_back();
v1.pop_back();
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;*/
}
void test05()
{
vector<int> v(10, 1);
vector<int> v1(v.begin(), v.end());
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
kl::vector<int> v2(10, 1);
kl::vector<int> v3(v2.begin(), v2.end());
for (auto e : v3)
{
cout << e << " ";
}
cout << endl;
}
//void test06()
//{
// kl::vector<int> foo(3, 100);
// for (auto e : foo)
// {
// cout << e << " ";
// }
// cout << endl;
// kl::vector<int> bar(5, 200);
// for (auto e : bar)
// {
// cout << e << " ";
// }
// cout << endl;
// foo.swap(bar);
// for (auto e : foo)
// {
// cout << e << " ";
// }
// cout << endl;
// for (auto e : bar)
// {
// cout << e << " ";
// }
// cout << endl;
//}
void test07()
{
vector<int> v(3, 10);
vector<int> v1;
v1 = v;
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
kl::vector<string> v2(3,"xxxx");
for (auto e : v2)
{
cout << e << " ";
}
cout << endl;
kl::vector<string> v3;
v3 = v2;
for (auto e : v3)
{
cout << e << " ";
}
cout << endl;
}
void test_vector6()
{
kl::vector<string> v;
v.push_back("111111111111111111");
v.push_back("222222222222222222");
v.push_back("333333333333333333");
v.push_back("444444444444444444");
v.push_back("555555555555555555");
for (auto& e : v)
{
cout << e << " ";
}
cout << endl;
kl::vector<string> v1(v);
for (auto& e : v1)
{
cout << e << " ";
}
cout << endl;
}
void test_vector7()
{
kl::vector<int> v(10u, 1);
kl::vector<string> v1(10, "1111");
kl::vector<int> v2(10, 1);
// vector<int> v;
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
kl::vector<int> v3(v.begin(), v.end());
for (auto e : v3)
{
cout << e << " ";
}
cout << endl;
string str("hello world");
kl::vector<char> v4(str.begin(), str.end());
for (auto e : v4)
{
cout << e << " ";
}
cout << endl;
int a[] = { 16,2,77,29 };
kl::vector<int> v5(a, a + 4);
for (auto e : v5)
{
cout << e << " ";
}
cout << endl;
}
int main()
{
//test01();
//test02();
//test03();
//test04();
//test05();
//test06();
//test07();
//test_vector6();
test_vector7();
return 0;
}
1.vector的介绍及使用
1. vector是表示可变大小数组的序列容器。
2. 就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。
3.与其它动态序列容器相比(deque, list and forward_list), vector在访问元素的时候更加高效,在末尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作,效率更低。比起list和forward_list统一的迭代器和引用更好。
2.vector的模拟实现
2.1使用memcpy拷贝问题
//拷贝构造 传统写法
vector(const vector<T>& v)
:_start(nullptr)
,_finish(nullptr)
,_end_of_storage(nullptr)
{
_start = new T[v.capacity()];
const_iterator it = v.begin();
T* tmp = _start;
//memcpy(_start, v._start, sizeof(T) * v.size());
while (it != v.end())
{
*_start = *it;
_start++, it++;
}
_start = tmp;
_finish = _start + v.size();
_end_of_storage = _start + v.capacity();
}
这里的拷贝构造不能只用简单的memcpy来进行拷贝赋值,当模板参数T是自定义类型的时候, 因为memcpy是浅拷贝,当自定义类型中有需要额外开辟的空间时候,这时memcpy只会把他们的指针所指向的地址拷贝过来,并没有为其开辟新的空间,这样在析构的时候,会造成深浅拷贝问题。
总结:如果对象中涉及到资源管理时,就不能使用memcpy进行对象之间的拷贝,因为memcpy是浅拷贝,否则可能会引起内存泄漏甚至程序崩溃 。
2.2迭代器失效的问题
其实迭代器失效的问题本质上就是底层的指针所指向的空间被销毁了,而使用了一块已经被释放的空间,造成了程序崩溃(如果继续使用已经失效的迭代器)。
这里经过我的测试,在Linux下和vs下两者对于其处理的方式截然不同,VS下比较暴力直接强制出错。然g++下就只要真正的内存泄漏才会报错。
下面一段代码可以很好的测试上述问题:
int main()
{
vector<int> v{ 1, 2, 3, 4 };
auto it = v.begin();
while (it != v.end())
{
if (*it % 2 == 0)
v.erase(it);
++it;
}
return 0;
}
解决迭代器失效的方式:在使用前,对迭代器重新赋值即可。
3.总结
因为vector的模拟实现和之前的string模拟实现大致相等所以就没有特别要说的地方,模拟实现最重要的就是要一点点的去巧去与库中的做对比然后再测试从中慢慢摸索。