1.迭代器失效
在上一篇中因为插入导致的扩容,扩容则pos指向的是之前的空间,导致了野指针的出现,没有扩容,使pos的位置意义改变,由于数据挪动,pos不再指向原来的位置,认为上面俩种迭代器失效。(vs有强制检查,如果出现上面情况会直接报错)
可以通过修正pos来保证迭代器的有效性。
先尾插4个数据,这里发if和else就是完成修正的,如果是偶数就删除,不是就下一个,如果是是删除再下一个就会出现问题,因为数据会挪动,就是说数据向前一步,it向后一步,则it就会跳过一个数据。
实现版本:
void test_vector3()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
//v.push_back(5);
print_container(v);
// 删除所有的偶数
auto it = v.begin();
while (it != v.end())
{
if (*it % 2 == 0)
{
v.erase(it);
}
else
{
++it;
}
}
print_container(v);
}
std版本:
std的vector,则v.erase()就是std的删除了,不是实现的,而std的erase会把删除位置的下一个位置传回来,所以要接收。
void test_vector3()
{
std::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
//v.push_back(5);
print_container(v);
// 删除所有的偶数
auto it = v.begin();
while (it != v.end())
{
if (*it % 2 == 0)
{
it=v.erase(it);
}
else
{
++it;
}
}
print_container(v);
}
2.实现resize
resize的实现需要讨论区间,输入的n小于原大小,或者是介于大小和容量之间,最后是大于容量。if判断,如果小于size则就减成n个大小,else就大于等于的情况,等于不用变,大于就扩大并且把第二个参数填到n个,这里T val=T()而不是等于0是因为要兼容多个类型,然后不是每个类型都可以用0初始化,T()是匿名对象,生成一个临时变量来初始化,每个类型都会走对应的初始化,内置类型就一般会赋值为0,而类就会走自己的构造。
void resize(size_t n, T val = T())
{
if (n < size())
{
_finish = _start + n;
}
else
{
reserve(n);
while (_finish < _start + n)
{
*_finish = val;
++_finish;
}
}
}
1.匿名对象
2.默认构造:
defalut可以构造一个成员变量都为默认值的类,像上面一样,int会变为0,需要注意的是,编译器生成一个默认构造的前提是没有然后一个构造函数,而拷贝构造出现,编译器也不会生成默认构造函数,因为拷贝构造也是构造函数。
//vector()
// /*: _start(nullptr)
// ,_finish(nullptr)
// ,_end_of_storage(nullptr)*/
//{}
C++11 前置生成默认构造
vector() = default;
3.拷贝构造
通过范围for,把v的每一个值都尾插到生成的类指向的空间上。
vector(const vector<T>& v)
{
reserve(v.size());
for (auto& e : v)
{
push_back(e);
}
}
void push_back(const T& x) { // 扩容 if (_finish == _end_of_storage) { reserve(capacity() == 0 ? 4 : capacity() * 2); } *_finish = x; ++_finish; }
4.赋值运算符重载
注释的代码虽然跟拷贝构造大差不差,但区别是拷贝构造是一个已经存在的对象去初始化另一个还没有初始化的对象,而赋值运算符重载是俩个已经存在的对象,没有注释则是通过std库的swap来实现,效率比模板swap的三次深拷贝快(若存在指向资源)。
// v1 = v3
/*vector<T>& operator=(const vector<T>& v)
{
if (this != &v)
{
clear();
reserve(v.size());
for (auto& e : v)
{
push_back(e);
}
}
return *this;
}*/
void swap(vector<T>& v)
{
std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_end_of_storage, v._end_of_storage);
}
// v1 = v3
//vector& operator=(vector v)
vector<T>& operator=(vector<T> v)
{
swap(v);
return *this;
}
5. 类模板的构造函数
// 类模板的成员函数,还可以继续是函数模版
template <class InputIterator>
vector(InputIterator first, InputIterator last)
{
while (first != last)
{
push_back(*first);
++first;
}
}
vector(size_t n, const T& val = T())
{
reserve(n);
for (size_t i = 0; i < n; i++)
{
push_back(val);
}
}
void test_vector6()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(4);
v1.push_back(4);
vector<int> v2(v1.begin(), v1.begin() + 3);
print_container(v1);
print_container(v2);
list<int> lt;
lt.push_back(10);
lt.push_back(10);
lt.push_back(10);
lt.push_back(10);
vector<int> v3(lt.begin(), lt.end());
print_container(lt);
print_container(v2);
vector<string> v4(10, "1111111");
print_container(v4);
vector<int> v5(10);
print_container(v5);
//vector<int> v6(10u, 1);
//print_container(v6);
vector<int> v7(10, 1);
print_container(v7);
}
可以用list的来初始vector,这就是模板的优势,可以兼容多个,灵活性高。
优势
- 灵活性:由于使用了模板,您可以从不同类型的容器或自定义的迭代器创建
vector
,提高了代码的重用性。 - 适应性:可以方便地适应不同数据源的输入,支持 STL 中的所有容器和任何自定义的迭代器类型。
vector<int> v7(10, 1);
print_container(v7);
运行测试6时出现了下面的错误,是因为有俩个选择,但是肯定是会去最合适的,那这样第一个就比较合适,俩个InputIterator都是int,编译器默认整数为int,所以会选择上一个,但是选了上一个,就会错误,因为10为first,1为finish,会一直循环,解决方法就是在10后面加个u表示这个10是size_t类型的。编译器则是写了很多个这种函数,为的就是有更多选择,让其能找到最合适的,从而不会出现错误。
6.memcpy浅拷贝
可以看到在没有扩容是,尾插字符串是可以的,但扩容是就出现乱码了,是因为随机数对应值刚好为这些,memcpy是一个一个字节拷贝的是浅拷贝,而v是有指向的内部资源的,所以会有俩个指向同一片区域,而当另一个析构是,剩下一个指向的就是没有权限的空间了,所以原空间的四个就没有了,只剩下第五个还在,把浅拷贝改进成深拷贝就行了,用string的赋值运算符重载来实现,这个是深拷贝的方法。
void test_vector7()
{
vector<string> v;
v.push_back("11111111111111111111");
v.push_back("11111111111111111111");
v.push_back("11111111111111111111");
v.push_back("11111111111111111111");
print_container(v);
v.push_back("11111111111111111111");
print_container(v);
}
string的赋值运算符重载:
string& operator=(const string& s)
{
if (this != &s)
{
delete[] _str;
_str = new char[s._capacity + 1];
strcpy(_str, s._str);
_size = s._size;
_capacity = s._capacity;
}
return *this;
7.总代码
vector.h
#pragma once
#include<assert.h>
#include<list>
#include<string>
#include<vector>
#include<iostream>
using namespace std;
namespace zym
{
template<class T>
class vector
{
public:
typedef T* iterator;
typedef const T* const_iterator;
//vector()
// /*: _start(nullptr)
// ,_finish(nullptr)
// ,_end_of_storage(nullptr)*/
//{}
C++11 前置生成默认构造
vector() = default;
vector(const vector<T>& v)
{
reserve(v.size());
for (auto& e : v)
{
push_back(e);
}
}
// 类模板的成员函数,还可以继续是函数模版
template <class InputIterator>
vector(InputIterator first, InputIterator last)
{
while (first != last)
{
push_back(*first);
++first;
}
}
vector(size_t n, const T& val = T())
{
reserve(n);
for (size_t i = 0; i < n; i++)
{
push_back(val);
}
}
/*vector(int n, const T& val = T())
{
reserve(n);
for (int i = 0; i < n; i++)
{
push_back(val);
}
}*/
void clear()
{
_finish = _start;
}
// v1 = v3
/*vector<T>& operator=(const vector<T>& v)
{
if (this != &v)
{
clear();
reserve(v.size());
for (auto& e : v)
{
push_back(e);
}
}
return *this;
}*/
void swap(vector<T>& v)
{
std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_end_of_storage, v._end_of_storage);
}
// v1 = v3
//vector& operator=(vector v)
vector<T>& operator=(vector<T> v)
{
swap(v);
return *this;
}
~vector()
{
if (_start)
{
delete[] _start;
_start = _finish = _end_of_storage = nullptr;
}
}
iterator begin()
{
return _start;
}
iterator end()
{
return _finish;
}
const_iterator begin() const
{
return _start;
}
const_iterator end() const
{
return _finish;
}
void reserve(size_t n)
{
if (n > capacity())
{
size_t old_size = size();
T* tmp = new T[n];
memcpy(tmp, _start, old_size * sizeof(T));
/*for (size_t i = 0; i < old_size; i++)
{
tmp[i] = _start[i];
}*/
delete[] _start;
_start = tmp;
_finish = tmp + old_size;
_end_of_storage = tmp + n;
}
}
void resize(size_t n, T val = T())
{
if (n < size())
{
_finish = _start + n;
}
else
{
reserve(n);
while (_finish < _start + n)
{
*_finish = val;
++_finish;
}
}
}
size_t size() const
{
return _finish - _start;
}
size_t capacity() const
{
return _end_of_storage - _start;
}
bool empty() const
{
return _start == _finish;
}
void push_back(const T& x)
{
// 扩容
if (_finish == _end_of_storage)
{
reserve(capacity() == 0 ? 4 : capacity() * 2);
}
*_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;
reserve(capacity() == 0 ? 4 : capacity() * 2);
pos = _start + len;
}
iterator end = _finish - 1;
while (end >= pos)
{
*(end + 1) = *end;
--end;
}
*pos = x;
++_finish;
return pos;
}
void erase(iterator pos)
{
assert(pos >= _start);
assert(pos < _finish);
iterator it = pos + 1;
while (it != end())
{
*(it - 1) = *it;
++it;
}
--_finish;
}
T& operator[](size_t i)
{
assert(i < size());
return _start[i];
}
const T& operator[](size_t i) const
{
assert(i < size());
return _start[i];
}
private:
iterator _start = nullptr;
iterator _finish = nullptr;
iterator _end_of_storage = nullptr;
};
/*void print_vector(const vector<int>& v)
{
vector<int>::const_iterator it = v.begin();
while (it != v.end())
{
cout << *it << " ";
++it;
}
cout << endl;
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
}*/
template<class T>
void print_vector(const vector<T>& v)
{
// 规定,没有实例化的类模板里面取东西,编译器不能区分这里const_iterator
// 是类型还是静态成员变量
//typename vector<T>::const_iterator it = v.begin();
auto it = v.begin();
while (it != v.end())
{
cout << *it << " ";
++it;
}
cout << endl;
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
}
template<class Container>
void print_container(const Container& v)
{
/*auto it = v.begin();
while (it != v.end())
{
cout << *it << " ";
++it;
}
cout << endl;*/
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
}
void test_vector3()
{
std::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
//v.push_back(5);
print_container(v);
// 删除所有的偶数
auto it = v.begin();
while (it != v.end())
{
if (*it % 2 == 0)
{
it=v.erase(it);
}
else
{
++it;
}
}
print_container(v);
}
void test_vector4()
{
int i = int();
int j = int(1);
int k(2);
vector<int> v;
v.resize(10, 1);
v.reserve(20);
print_container(v);
cout << v.size() << endl;
cout << v.capacity() << endl;
v.resize(15, 2);
print_container(v);
v.resize(25, 3);
print_container(v);
v.resize(5);
print_container(v);
}
void test_vector6()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(4);
v1.push_back(4);
vector<int> v2(v1.begin(), v1.begin() + 3);
print_container(v1);
print_container(v2);
list<int> lt;
lt.push_back(10);
lt.push_back(10);
lt.push_back(10);
lt.push_back(10);
vector<int> v3(lt.begin(), lt.end());
print_container(lt);
print_container(v2);
vector<string> v4(10, "1111111");
print_container(v4);
vector<int> v5(10);
print_container(v5);
//vector<int> v6(10u, 1);
//print_container(v6);
vector<int> v7(10u, 1);
print_container(v7);
}
void test_vector7()
{
vector<string> v;
v.push_back("11111111111111111111");
v.push_back("11111111111111111111");
v.push_back("11111111111111111111");
v.push_back("11111111111111111111");
print_container(v);
v.push_back("11111111111111111111");
print_container(v);
}
}
test.cpp
#include"vector.h"
int main()
{
zym::test_vector7();
}