房地产公司网站下载桂林市临桂区
news/
2025/10/4 4:33:43/
文章来源:
房地产公司网站下载,桂林市临桂区,洛阳seo外包公司费用,物流网站开发实训目录
vector的使用
vector的定义
vector iterator的使用
vector空间增长问题
vector增删查改
vector深度剖析及模拟实现
vector核心接口模拟实现
使用memcpy拷贝问题
迭代器失效问题 vector的使用
vector的定义 C中#xff0c;vector是一个模版#xff0c;第一个参…目录
vector的使用
vector的定义
vector iterator的使用
vector空间增长问题
vector增删查改
vector深度剖析及模拟实现
vector核心接口模拟实现
使用memcpy拷贝问题
迭代器失效问题 vector的使用
vector的定义 C中vector是一个模版第一个参数是类型T第二个参数暂且不考虑。
vectorint v;
我们可以通过上面这句代码将参数T给成int那么vector中所包含的元素就是int。
重点1.vector() 无参构造 重点2.vector (const vector x) 拷贝构造 3.vectorsize_type n, const value_type val value_type() 构造并初始化n个val 4.vectorsize_type n, const value_type val value_type() 使用迭代器进行初始化构造 vector iterator的使用
重点1.beginend 获取第一个数据位置的iterator/const_iterator获取最后一个数据的下一个位置的iterator/const_iterator 2.rbeginrend 获取最后一个数据位置的reverse_iterator获取第一个数据前一个位置的reverse_iterator vector空间增长问题
1.size和capacity size用来获取数据个数capacity获取容量大小 2.empty 判断是否为空 重点3.resize 改变vector的size 重点4.reserve 改变vector的capacity 关于空间增长问题有几个点需要注意
1.capacity的代码在vs和g下分别运行会发现vs下capacity是按1.5倍增长的g是按2倍增长的。这个问题经常会考察不要固化的认为vector增容都是2倍具体增长多少是根据具体的需求定义的。vs是PJ版本STLg是SGI版本STL。
2.reserve只负责开辟空间如果确定知道需要用多少空间reserve可以缓解vector增容的代价缺陷问题。
3.resize在开空间的同时还会进行初始化影响size。 测试vector的扩容机制
void TestVectorExpand()
{size_t sz; vectorint v; sz v.capacity();cout making v grow:\n; for (int i 0; i 100; i) {v.push_back(i);if (sz ! v.capacity()) {sz v.capacity();cout capacity changed: sz \n;}}
}
在vs2019下的运行结果 结论vs下使用的STL基本是按照1.5倍方式扩容 在g下的运行结果 结论linux下使用的STL基本是按照2倍方式扩容 //如果已经确定vector中要存储元素大概个数可以提前将空间设置足够
//就可以避免边插入边扩容导致效率低下的问题了
void TestVectorExpandOP()
{vectorintv;size_tszv.capacity();v.reserve(100);//提前将容量设置好可以避免一遍插入一遍扩容coutmaking bar grow:\n;for(inti0;i100;i){v.push_back(i);if(sz!v.capacity()){szv.capacity();coutcapacity changed: sz\n;}}
}
vector增删查改
重点1.push_back 尾插 重点2.pop_back 尾删 注意vector未提供头插头删因为那样效率很低
3.find 查找。注意这个是算法模块实现不是vector的成员接口 4.insert 在position之前插入val 5.erase 删除position位置的数据 6.swap 交换两个vector的数据空间 7.operator[ ] 像数组一样访问。越界时会发生assert报错 更进一步
除了将vector中的参数T初始化为int、double等内置类型外还可以将其初始化为string、vectorint等。
void test_vector()
{vectorstring v;string s1(苹果);v.push_back(s1);v.push_back(string(香蕉));v.push_back(草莓);
}
vectorvectorint v;
下面画出这个的示意图以便理解 对于vectorvectorint v这种我们可以把它看成一个二维数组可以通过v[i][j]的形式去访问其成员那么我们难免会联想到二维数组的访问也是v[i][j]这种形式那它们有区别吗其实它们的区别很大
对于静态的二维数组v[i][j]其底层是一个一维数组数组名v表示第一行的地址vi表示第i行地址从0行开始*(vi)表示第i行第一个元素的地址*(*(vi)j)表示第i行第j个元素即v[i][j]。 对于vectorvectorint vv[i][j]可以看成两次函数调用第一次调用相当于vv.operator[](i)其返回值为vectorint对象第二次调用相当于vv.operator[](i).operator[](j)。
vector深度剖析及模拟实现 如果按照之前string的习惯start就是afinish就是asizeend_of_storage就是acapacity。
vector核心接口模拟实现
#include assert.hnamespace ghs
{templateclass Tclass vector{public:typedef T* iterator;typedef const T* const_iterator;const_iterator begin()const{return _start;}const_iterator end()const{return _finish;}iterator begin(){return _start; }iterator end(){return _finish;}vector(){}//v2(v1)vector(const vectorT v){reserve(v.capacity());//引用防止深拷贝for (auto ch : v){push_back(ch);}}//vectorint v { 1,2,3,4,5,6,7,8,9 };vector(initializer_listT il){reserve(il.size());for (auto e : il){push_back(e);}}//类模板的成员函数可以是函数模版template class InputIteratorvector(InputIterator first, InputIterator last){while (first ! last){push_back(*first);first;}}//const T val T() 构造匿名对象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 swap(vectorT v){std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_endofstorage, v._endofstorage);}//v1 v3,v是v3的拷贝vectorT operator(vectorT v){swap(v);return *this;}size_t capacity()const{return _endofstorage - _start;}size_t size()const{return _finish - _start;}~vector(){delete[] _start;_start _finish _endofstorage nullptr;}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 reserve(size_t n){if (n capacity()){T* tmp new T[n];size_t old_size size();//memcpy(tmp, _start, old_size * sizeof(T));for (size_t i 0; i old_size; i){tmp[i] _start[i];//这样如果T是string走的深拷贝}delete[] _start;_start tmp;_finish _start old_size;_endofstorage _start n;}}void resize(size_t n, const T val T()){if (n size()){reserve(n);//插入while (_finish _start n){*_finish val;_finish;}}else{//删除_finish _start n;}}void push_back(const T val){if (_finish _endofstorage){reserve(capacity() 0 ? 4 : 2 * capacity());}*_finish val;_finish;}void pop_back(){/*assert(!empty());--_finish;*/erase(--end());}bool empty(){return _start _finish;}void insert(iterator pos, const T val){assert(pos _start);assert(pos _finish);if (_finish _endofstorage){size_t len pos - _start;reserve(capacity() 0 ? 4 : 2 * capacity());//如果扩容了要更新pospos _start len;}iterator end _finish - 1;while (end pos){*(end 1) *end;end--;}*pos val;_finish;}iterator erase(iterator pos){assert(pos _start);assert(pos _finish);iterator it pos 1;while (it _finish){*(it - 1) *it;it;}--_finish;//返回pos用于迭代器更新return pos;}private:iterator _start nullptr;iterator _finish nullptr;iterator _endofstorage nullptr;};templateclass Tvoid print_vector(const vectorT v) {for (size_t i 0; i v.size(); i){cout v[i] ;}cout endl;//加一个typename告诉编译器后边那个是一个类型否则报错//typename vectorT::const_iterator it v.begin();/*auto it v.begin();while (it ! v.end()){cout *it ;it;}cout endl;for (auto c : v){cout c ;}cout endl;*/}
}
使用memcpy拷贝问题
假设模拟实现的vector中的reserve接口中使用memcpy进行的拷贝以下代码会发生什么问题
void testvector()
{vectorint v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);v1.push_back(6);v1.push_back(7);v1.push_back(8);
} 1. memcpy是内存的二进制格式拷贝将一段内存空间中内容原封不动的拷贝到另外一段内存空间中。 2. 如果拷贝的是自定义类型的元素memcpy既高效又不会出错但如果拷贝的是自定义类型元素并且 自定义类型元素中涉及到资源管理时就会出错因为memcpy的拷贝实际是浅拷贝。 结论如果对象中涉及到资源管理时千万不能使用memcpy进行对象之间的拷贝因为memcpy是浅拷贝否则可能会引起内存泄漏甚至程序崩溃。
在上面我们自己模拟实现的扩容接口中
void reserve(size_t n)
{if (n capacity()){T* tmp new T[n];size_t old_size size();//memcpy(tmp, _start, old_size * sizeof(T));for (size_t i 0; i old_size; i){tmp[i] _start[i];//这样如果T是string走的深拷贝}delete[] _start;_start tmp;_finish _start old_size;_endofstorage _start n;}
}
我们使用for循环赋值的方式进行拷贝这样即使T是自定义类型比如是string那么会去调string的赋值string的赋值是深拷贝。
迭代器失效问题
迭代器的主要作用就是让算法能够不用关心底层数据结构其底层实际就是一个指针或者是对指针进行了封装比如vector的迭代器就是原生态指针T* 。因此迭代器失效实际就是迭代器底层对应指针所指向的空间被销毁了而使用一块已经被释放的空间造成的后果是程序崩溃(即如果继续使用已经失效的迭代器程序可能会崩溃)。
对于vector可能会导致其迭代器失效的操作有 1. 会引起其底层空间改变的操作都有可能是迭代器失效比如resize、reserve、insert、assign、push_back等。 2. 指定位置元素的删除操作--erase erase删除pos位置元素后pos位置之后的元素会往前搬移没有导致底层空间的改变理论上讲迭代器不应该会失效但是如果pos刚好是最后一个元素删完之后pos刚好是end的位置而end位置是没有元素的那么pos就失效了。因此删除vector中任意位置上元素时vs就认为该位置迭代器失效了。
下面实现了删除vector中偶数的功能:
void testvector()
{vectorint v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);v1.push_back(6);v1.push_back(7);v1.push_back(8);print_vector(v1);//删除偶数vectorint::iterator it v1.begin();while (it ! v1.end()){if (*it % 2 0){it v1.erase(it);}else{it;}}print_vector(v1);
}
其中我们每次使用了it v1.erase(it);更新迭代器。
迭代器失效解决办法在使用前对迭代器重新赋值即可。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/926592.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!