赞
踩
目录
为了与库里实现的更接近一些,先来看一下STL中是如何实现vector的(这里不是PJ版,PJ版稍微晦涩一点不容易理解,这里采用Linux下g++的版本)这里仅就大体框架做个简单介绍,其中复杂的概念不做过多解释。
首先是vector定义的模板参数T和Alloc,这是空间配置器是一种底层实现机制,使用角度不用管。
可以看到源码做了很多typedef,主要是对格式的控制和方便理解编写。其中将T* typedef成了iterator,这个要注意,后面protected 成员变量会用到。
这里成员变量就用到了刚刚typedef的iterator,实际上就是T* start ; T* finish; T* end_of_storage;
T就是实例化模板参数。好像与我们设想的变量不太一样,我们设想的应该是有size和capacity的,但是这里全部统一使用指针,其实只是改变了使用方式,本质还是一样的。
假设存在size(有效数据个数),capacity(容量),那么finish也可以表示成start+size,end_of_storage也可以表示成strat+capacity,本质是一样的。
后面是各个接口的实现,后面我们自己实现的时候具体说明,先把大框架搭建起来。
- namespace bc
- {
- template<class T>
- class vector
- {
- public:
- typedef T* iterator;
-
- private:
- iterator _start;
- iterator _finish;
- iterator _end_of_storage;
- };
- }
为了避免和库里的冲突,将我们的实现代码封在命名空间内,库里的繁杂的typedef我们省略,只保留基本的T* 的重命名和成员变量表示。
vector.h
- #pragma once
-
- #include<iostream>
- #include<vector>
- #include<assert.h>
-
- using namespace std;
-
- namespace bc
- {
- template<class T>
- class vector
- {
- public:
- typedef T* iterator;
- vector()
- :_start(nullptr)
- , _finish(nullptr)
- , _end_of_storage(nullptr)
- { }
-
- //拷贝构造写法一
- //vector(const vector<T>& v)
- // : _start(nullptr)
- // , _finish(nullptr)
- // , _end_of_storage(nullptr)
- //{
- // reserve(size());
- // for (auto& e : v) {
- // push_back(e);
- // }
- //}
-
-
- //拷贝构造现代写法
- template<class InputIterator>
- vector(InputIterator first, InputIterator last)
- : _start(nullptr)
- , _finish(nullptr)
- , _end_of_storage(nullptr)
- {
- while (first != last) {
- push_back(*first);
- first++;
- }
- }
-
- vector(vector<T>& v)
- : _start(nullptr)
- , _finish(nullptr)
- , _end_of_storage(nullptr)
- {
- vector<T> tmp(v.begin(), v.end());
- swap(tmp);
- }
-
- vector(size_t n, const T& val= T())
- : _start(nullptr)
- , _finish(nullptr)
- , _end_of_storage(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)
- , _end_of_storage(nullptr)
- {
- reserve(n);
- for (int i = 0; i < n; ++i) {
- push_back(val);
- }
- }
-
- ~vector() {
- delete[]_start;
- _start = _finish = _end_of_storage = nullptr;
- }
-
- vector<T>& operator=(vector<T> v) {
- swap(v);
- return *this;
- }
-
- size_t size()const {
- return _finish - _start;
- }
- size_t capacity()const {
- return _end_of_storage - _start;
- }
-
- iterator begin() {
- return _start;
- }
- iterator end() {
- return _finish;
- }
- const iterator begin() const {
- return _start;
- }
- const iterator end() const {
- return _finish;
- }
-
- bool empty()const {
- return _finish == _start;
- }
-
- void clear() {
- _finish = _start;
- }
-
- void swap(vector<T>& v) {
- std::swap(_start, v._start);
- std::swap(_finish, v._finish);
- std::swap(_end_of_storage, v._end_of_storage);
- }
- 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 resize(size_t n, T val = T()) {
- if (n > capacity()) {
- reserve(n);
- }
- if (n > size() && n <= capacity()) {
- while (_finish < _start + n) {
- *_finish = val;
- ++_finish;
- }
- }
- if (n <= size()) {
- _finish = _start + n;
- }
- }
-
- void reserve(size_t n) {
- if (n > capacity()) {
- size_t oldsize = size();
- T* tmp = new T[n];
- if (_start != nullptr) {
- memcpy(tmp, _start, sizeof(T) * oldsize);
- /*for (size_t i = 0; i < oldsize; ++i) {
- tmp[i] = _start[i];
- }*/
- delete[]_start;
- }
- _start = tmp;
- _finish = tmp + oldsize;
- _end_of_storage = _start + n;
- }
- }
-
-
-
- void push_back(const T& x) {
- if (_finish == _end_of_storage) {
- size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity();
- reserve(newcapacity);
- }
- *_finish = x;
- ++_finish;
- }
-
-
- void pop_back() {
- assert(!empty());
- _finish--;
- }
-
- //迭代器失效
- iterator insert(iterator pos, const T& x) {
- assert(pos >= _start);
- assert(pos < _finish);
- if (_finish == _end_of_storage) {
- size_t len = pos - _start;
- size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity();
- reserve(newcapacity);
- pos = _start + len;
- }
- iterator end = _finish - 1;
- while (end >= pos) {
- *(end + 1) = *(end);
- --end;
- }
- *pos = x;
- _finish++;
- return pos;
- }
-
- iterator erase(iterator pos) {
- assert(pos >= _start);
- assert(pos < _finish);
- iterator begin = pos + 1;
- while (begin < _finish) {
- *(begin-1) = *(begin);
- ++begin;
- }
- _finish--;
- return pos;
- }
-
- private:
- iterator _start;
- iterator _finish;
- iterator _end_of_storage;
- };
下面是我给出的测试用例:
vector.h
- void Test1() {
- vector<int>a;
- a.push_back(1);
- a.push_back(1);
- a.push_back(1);
- a.push_back(1);
- a.push_back(1);
- cout << a.capacity() << endl;
- for (size_t i = 0; i < a.size(); ++i)
- {
- cout << a[i] << " ";
- }
- cout << endl;
-
- vector<int>::iterator it = a.begin();
- while (it != a.end()) {
- cout << (*it) << " ";
- it++;
- }
- cout << endl;
-
- //a.resize(2);
- for (auto e : a) {
- cout << e << " ";
- }
- cout << endl;
-
- cout << a.empty() << endl;
-
- a.pop_back();
-
- for (auto e : a) {
- cout << e << " ";
- }
- cout << endl;
- }
-
- void Test2() {
- vector<int> a;
- a.push_back(1);
- a.push_back(1);
- a.push_back(1);
- a.push_back(1);
- for (auto e : a) {
- cout << e << " ";
- }
- cout << endl;
-
- a.insert(a.begin(), 0);
-
- for (auto e : a) {
- cout << e << " ";
- }
- cout << endl;
-
- vector<int>::iterator it = find(a.begin(), a.end(), 1);
- if (it != a.end()) {
- a.insert(it, 2);
- }
- for (auto e : a) {
- cout << e << " ";
- }
- cout << endl;
-
- (*it)++;
- for (auto e : a) {
- cout << e << " ";
- }
- cout << endl;
- }
-
- void Test3() {
- vector<int> v;
- v.push_back(1);
- v.push_back(2);
- v.push_back(3);
- v.push_back(4);
- v.push_back(4);
- v.push_back(5);
- vector<int>::iterator it = v.begin();
- while (it != v.end()) {
- if ((*it) % 2 == 0) {
- it = v.erase(it);
- }
- else {
- ++it;
- }
- }
- for (auto e : v) {
- cout << e << " ";
- }
- cout << endl;
- }
-
- void Test4() {
- vector<int> v;
- v.push_back(1);
- v.push_back(1);
- v.push_back(1);
- v.push_back(1);
- vector<int> a(v);
- for (auto e : a) {
- cout << e << " ";
- }
- cout << endl;
-
- vector<int> b;
- b = a;
- for (auto e : b) {
- cout << e << " ";
- }
- cout << endl;
-
- vector<int>c(10, 1);
- for (auto e : c) {
- cout << e << " ";
- }
- cout << endl;
- }
-
- void Test5()
- {
- vector<vector<int>> vv;
- vector<int> v(4, 1);
- vv.push_back(v);
- vv.push_back(v);
- vv.push_back(v);
- vv.push_back(v);
- 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;
- }
- }
test.cpp
- #include"vector.h"
-
- int main()
- {
- bc::Test1();
- bc::Test2();
- bc::Test3();
- bc::Test4();
- bc::Test5();
-
- /*vector<int> v;
- v.push_back(1);
- v.push_back(2);
- v.push_back(3);
- v.push_back(4);
- v.push_back(5);
- std::vector<int>::iterator it = v.begin();
- while (it != v.end()) {
- if ((*it) % 2 == 0) {
- v.erase(it);
- }
- ++it;
- }
- for (auto e : v) {
- cout << e << " ";
- }
- cout << endl;*/
-
- return 0;
- }
以上是常用接口的大致实现,基本功能包含在内,还有些不太常用的接口没有实现。
在测试vector<vector<int>>二维数组的时候,发现一个奇怪的现象:
当创建好vector<vector<int>> vv模型,并创建出内置数组vector<int> v (4,1)后,此时想要设定行数,也就是通过push_back插入行实现时,如果插入4个以内,没有问题,超过4个就会报错。
由此我们可以判定问题出在扩容上,具体我画图来解释。
对于vector<vector<int>>模型要有一定理解,外部的大类型是vector<>,< >里面的类型是vector<int>,所以先从内部开始创建,vector<int> v(4,1) 构造一个{1,1,1,1}的一维数组,里面构建好了,在外面通过push_back插入,相当于插入一个一个这样的一维数组,这样就构建了二维数组,push_back多少次就相当于有多少行,里面4相当于列。
vector<int> v 数组里面的元素是int类型的,外面通过_start 指针指向v数组,指针是int* 类型的,一个指针指向一个v数组,外面还有一个_start指针指向整个vector<vector<int>>,指针类型是vector<int>*
建好二维数组后来看扩容问题,当调用reserve时,需要开辟新空间tmp,用memcpy将数据传给tmp 。
而memcpy是按内存将数据拷贝给tmp的,这里的拷贝是浅拷贝,这就会导致一个问题,tmp最后也会指向_start 空间,
然后memcpy结束就是delete[]_start,delete会调用析构函数将_start空间释放,这下tmp指向的空间get不到了,tmp就是野指针了。
所以要想解决这个问题,就要解决内层浅拷贝的问题,将其改为深拷贝,这样外层tmp对象深拷贝,里层tmp数据也进行深拷贝,就不会出问题了。
解决方案:1、不用memcpy,利用operator = 重载函数将数据一个一个拷贝给tmp
- void reserve(size_t n)
- {
- if (n > capacity())
- {
- size_t oldSize = size();
- T* tmp = new T[n];
-
- if (_start)
- {
- //memcpy(tmp, _start, sizeof(T)*oldSize);
- for (size_t i = 0; i < oldSize; ++i)
- {
- tmp[i] = _start[i];
- }
-
- delete[] _start;
- }
- _start = tmp;
- _finish = tmp + oldSize;
- _endofstorage = _start + n;
- }
- }
tmp[i] = _start[i] 将_start[i] 一个一个拷贝给tmp[i],这里调用operator= 是深拷贝。
- vector<T>& operator=(vector<T> v)
- {
- swap(v);
- return *this;
- }
但是这种方法缺点是效率太低。在C++11 中会有更好的方式解决上述问题。
以上就是深层拷贝的内容,关于底层实现还有其他不同版本,但因为复杂度等原因我们是按Linux g++使用的库实现的,感谢浏览!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。