中国诚信建设网站,宠物喂养网页设计模板以及代码,做网站需要用到的符号语言,莱州人社局网站目录
vector常用接口
vector 迭代器失效问题
vector中深浅拷贝问题 vector的数据安排以及操作方式#xff0c;与array非常相似。两者的唯一差别在于空间的运用的灵活性。array 是静态空间#xff0c;一旦配置了就不能改变#xff1b;要换个大(或小) 一点的房子#x…
目录
vector常用接口
vector 迭代器失效问题
vector中深浅拷贝问题 vector的数据安排以及操作方式与array非常相似。两者的唯一差别在于空间的运用的灵活性。array 是静态空间一旦配置了就不能改变要换个大(或小) 一点的房子可以一切琐细得由客户端自已来:首先配置一块新空间 然后将元素从旧址一 一搬往新址再把原来的空间释还给系统。vector是动态空间随着元素的加入它的内部机制会自行扩充空间以容纳新元素。因此vector 的运用对于内存的合理利用与运用的灵活性有很大的帮助我们再也不必因为害怕空间不足而一开始就要求一个大块头array了我们可以安心使用vector,吃多少用多少。
vector定义 templateclass T class vector { public: typedef T* iterator; typedef const T* const_iterator; private: iterator _start ; //表示目前使用空间的头 iterator _finish; //表示目前使用空间的尾 iterator _end_of_storage; //表示可用空间的尾 } vector常用接口
push_back( ) 成员函数在vector的末尾插入值如果有必要会扩展vector的大小。pop_back( ) 成员函数在vector的末尾删除值。size( ) 函数显示vector的大小。begin( ) 函数返回一个指向vector开头的迭代器。end( ) 函数返回一个指向vector末尾的迭代器。empty() 判断vector是否为空。find() 查找。注意这个是算法模块实现不是vector的成员接口insert() 在position之前插入valerase() 删除position位置的数据swap() 交换两个vector的数据空间operator[] 像数组一样使用下标访问
size 是当前 vector 容器真实占用的大小也就是容器当前拥有多少个容器。
capacity 是指在发生 realloc 前能允许的最大元素数即预分配的内存空间。
当然这两个属性分别对应两个方法resize() 和 reserve()。
使用 resize() 容器内的对象内存空间是真正存在的。
使用 reserve() 仅仅只是修改了 capacity 的值容器内的对象并没有真实的内存空间(空间是野的)。
capacity的代码在vs和g下分别运行会发现vs下capacity是按1.5倍增长的g是按2倍增长的。 具体增长多少是根据具体的需求定义的。vs是PJ版本STLg是SGI版本STL。 reserve只负责开辟空间如果确定知道需要用多少空间reserve可以缓解vector增容的代价缺陷问题。 resize在开空间的同时还会进行初始化影响size。
此时切记使用 [] 操作符访问容器内的对象很可能出现数组越界的问题。
vector 迭代器失效问题
迭代器的主要作用就是让算法能够不用关心底层数据结构其底层实际就是一个指针或者是对指针进行了封装比如vector的迭代器就是原生态指针T* 。迭代器失效就是迭代器底层对应指针所指向的空间倍销毁了,导致使用了一块已经被释放了的空间。
迭代器失效分为两大类
1.扩容导致野指针 我们发现push_back尾插4个后调用insert会出现随机值。问题就是扩容导致pos迭代器失效原因在于pos没有更新导致非法访问野指针。
当尾插4个数字后再头插一个数字发生扩容根据reserve扩容机制扩容地址改变迭代器就会失效insert中发生扩容迭代器指向的空间被释放迭代器本质上就是一个野指针。_ start和_ finish都会更新但是这个插入的位置pos没有更新此时pos依旧执行旧空间再者reserve后会释放旧空间此时的pos就是野指针导致*pos x就是对非法访问野指针。因为pos迭代器没有更新所以后续挪动数据并没有实现而插入数据是对释放的空间进行操作同样没有意义。这也就是说不论你在哪个位置插入都没有效果。
解决办法
扩容后更新pos解决pos失效的问题。
iterator insert(iterator pos, const T val){assert(pos _start);assert(pos _finish);//扩容地址改变迭代器会失效//insert中发生扩容it指向的空间被释放it本质上就是一个野指针if (_finish _end_of_storage){size_t len pos - _start;reserve(capacity() 0 ? 4 : capacity() * 2);//扩容后更新pos解决pos失效的问题pos _start len;}iterator end _finish - 1;while (pos end){*(end 1) *end;--end;}*pos val;_finish;return pos;}
2.迭代器指向位置意义改变
比如要求删除vector中所有的偶数 erase删除pos位置元素后pos位置之后的元素会往前移动没有导致底层空间的改变理论上讲迭代器不会失效但是如果pos位置刚好是最后一个元素删完之后pos刚好是end的位置而end的位置是没有有效元素的那么pos就失效了。因此删除vector中任意位置元素时均认为该位置上迭代器失效。我们应该在使用的时候注意让迭代器指向有效的位置。
迭代器失效后代码并不一定会崩溃但是运行结果肯定不对如果it不在begin和end范围内肯定会崩溃。
vector中深浅拷贝问题
拷贝构造函数 memcpy是浅拷贝当T是内置类型的时候这个拷贝函数没什么问题当时当T是自定义类型的时候就会出现问题比如T是string类型。 如果此时我们使用的是memcpy函数进行拷贝构造的话那么拷贝构造出来的vector中每个string的成员变量的值将与被拷贝的vector中每个string的成员变量的值相同即两个vector当中的每个对应的string成员都指向同一个字符串空间。
解决办法 _start[i] _v[i] 本质是调用string类的赋值运算符重载函数进行深拷贝。
扩容也需要注意浅拷贝的问题。
扩容时调用的memcpy是浅拷贝就会导致先前存储的数据被memcpy后再delete就全删掉变成随机值了。vector调用析构函数析构掉原来的对象每个对象又调用自身的析构函数把指向的空间释放掉然后就会出现随机值。 我们析构旧空间的时候析构的是对象数组每个数组调用自身的析构函数会析构数组的空间。我们用memcpy浅拷贝时拷贝的临时对象和原来的对象指向同一块空间所以旧空间被销毁后我们扩容的新空间中的对象变成野指针访问的数据都是随机值。我们用for循环调用vector的赋值运算符重载可以将旧空间的数据拷贝到新空间这样析构旧空间就不会影响新空间。