博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
vector的构造与内存管理
阅读量:2224 次
发布时间:2019-05-08

本文共 7417 字,大约阅读时间需要 24 分钟。

1.vector的数据结构

[cpp]
  1. template <class T, class Alloc = alloc>    
  2. class vector {  
  3. ...  
  4. protected:  
  5.   iterator start;                    //表示目前已使用空间的头   
  6.   iterator finish;                 //表示目前已使用空间的尾   
  7. iterator end_of_storage;         //表示目前可用空间的尾(已分配)   
  8. ...  
  9. public:  
  10.   iterator begin() { return start; }  
  11.   const_iterator begin() const { return start; }  
  12.   iterator end() { return finish; }  
  13.   const_iterator end() const { return finish; }  
  14.   reverse_iterator rbegin() { return reverse_iterator(end()); }  
  15.   const_reverse_iterator rbegin() const {   
  16.     return const_reverse_iterator(end());   
  17.   }  
  18.   reverse_iterator rend() { return reverse_iterator(begin()); }  
  19.   const_reverse_iterator rend() const {   
  20.     return const_reverse_iterator(begin());   
  21. }  
  22. //求取已使用容量   
  23.   size_type size() const { return size_type(end() - begin()); }  
  24.   size_type max_size() const { return size_type(-1) / sizeof(T); }  
  25.   //求取目前可使用空间容量   
  26.   size_type capacity() const { return size_type(end_of_storage - begin()); }  
  27.   bool empty() const { return begin() == end(); }  
  28. ...  
  29. }  
template 
class vector {...protected: iterator start; //表示目前已使用空间的头 iterator finish; //表示目前已使用空间的尾iterator end_of_storage; //表示目前可用空间的尾(已分配)...public: iterator begin() { return start; } const_iterator begin() const { return start; } iterator end() { return finish; } const_iterator end() const { return finish; } reverse_iterator rbegin() { return reverse_iterator(end()); } const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } reverse_iterator rend() { return reverse_iterator(begin()); } const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }//求取已使用容量 size_type size() const { return size_type(end() - begin()); } size_type max_size() const { return size_type(-1) / sizeof(T); } //求取目前可使用空间容量 size_type capacity() const { return size_type(end_of_storage - begin()); } bool empty() const { return begin() == end(); }...}

 

2.vector的构造与内存管理

2.1初始化

容器的构造函数

1C<T> c;   创建空容器

2C c(c2);      创建c2的一个副本,Cc2必须有相同的容器类型及元素类型

3C c(b,e);   创建c,其元素是迭代器be范围之间元素的副本。

       对于这一条,使用迭代器的时候,不要求容器类型相同。容器内的元素类型也可以不同,只要他们相互兼容,能够将要复制的元素转化为所构建的新容器的元素类型,即可以实现复制。

4C c(n,t);   n个值为t的元素创建容器c。(仅适用于顺序容器)。参数的顺序和语言相适应,nt

5C c(n);    创建含n个默认值的容器c。(仅适用于顺序容器)。

 

       vector是顺序容器,所以上述5种构造函数都可以使用。

[cpp]
  1. template <class T, class Alloc = alloc>    
  2. class vector {  
  3. ...  
  4. protected:  
  5. //vector缺省使用alloc作为空间配置器,并据此另外定义了一个data_allocator,为的是更方便以元素大小为配置单位   
  6. //专属空间配置器,每次配置一个元素大小   
  7.   typedef simple_alloc<value_type, Alloc> data_allocator;  
  8. ...  
  9.   vector() : start(0), finish(0), end_of_storage(0) {}  
  10.   vector(size_type n, const T& value) { fill_initialize(n, value); }  
  11.   vector(int n, const T& value) { fill_initialize(n, value); }  
  12.   vector(long n, const T& value) { fill_initialize(n, value); }  
  13.   explicit vector(size_type n) { fill_initialize(n, T()); }  
  14. ...  
  15. void fill_initialize(size_type n, const T& value) {  
  16.     start = allocate_and_fill(n, value);  //配置空间并设初值   
  17.     finish = start + n;                 // 调整范围   
  18.     end_of_storage = finish;            // 调整范围   
  19.   }  
  20. iterator allocate_and_fill(size_type n, const T& x) {  
  21.     iterator result = data_allocator::allocate(n); //配置n个元素空间   
  22.     __STL_TRY {  
  23.       // 全局函数,将result所指的未初始化空间设定为n个初值为x的变量   
  24.       // 定义于 <stl_uninitialized.h>。   
  25.       uninitialized_fill_n(result, n, x);  //全局函数   
  26.       return result;  
  27.     }  
template 
class vector {...protected://vector缺省使用alloc作为空间配置器,并据此另外定义了一个data_allocator,为的是更方便以元素大小为配置单位//专属空间配置器,每次配置一个元素大小 typedef simple_alloc
data_allocator;... vector() : start(0), finish(0), end_of_storage(0) {} vector(size_type n, const T& value) { fill_initialize(n, value); } vector(int n, const T& value) { fill_initialize(n, value); } vector(long n, const T& value) { fill_initialize(n, value); } explicit vector(size_type n) { fill_initialize(n, T()); }...void fill_initialize(size_type n, const T& value) { start = allocate_and_fill(n, value); //配置空间并设初值 finish = start + n; // 调整范围 end_of_storage = finish; // 调整范围 }iterator allocate_and_fill(size_type n, const T& x) { iterator result = data_allocator::allocate(n); //配置n个元素空间 __STL_TRY { // 全局函数,将result所指的未初始化空间设定为n个初值为x的变量 // 定义于
。 uninitialized_fill_n(result, n, x); //全局函数 return result; }

 

!!!uninitialized_fill_n()会根据第一参数的型别特性(type traits)决定使用算法fill_n()或反复调用construct()来完成任务。!!!

 

2.2 push_back()操作时vector内部的过程

    push_back()操作将新元素插入容器尾部,该函数首先检查是否还有备用空间(finish!=end_of_storage),如果有那么就直接在备用空间上构造元素,并调整迭代器finish。如果没有备用空间了(finish= end_of_storage),就扩充空间(重新配置,移动数据,释放原空间)。

[cpp]
  1.  void push_back(const T& x) {  
  2.     if (finish != end_of_storage) {  // 还有备用空间   
  3.       construct(finish, x);         // 直接在备用空间中构建元素   
  4.       ++finish;                             // 调整范围   
  5.     }  
  6.     else                                  // 已无备用空间   
  7.       insert_aux(end(), x);           
  8.   }  
  9.   
  10. template <class T, class Alloc>  
  11. void vector<T, Alloc>::insert_aux(iterator position, const T& x) {  
  12.   if (finish != end_of_storage) {  // 还有备用空间   
  13.     // 在备用空间起始处构造一个元素,并以vector最后一个元素值为其初值     
  14.     construct(finish, *(finish - 1));  
  15.     ++finish;  
  16.     // 以下做啥用?   
  17.     T x_copy = x;  
  18.     copy_backward(position, finish - 2, finish - 1);  
  19.     *position = x_copy;  
  20.   }  
  21.   else {        // 已無備用空間   
  22.     const size_type old_size = size();//此时的size()等同于capacity()   
  23.     const size_type len = old_size != 0 ? 2 * old_size : 1;  
  24.     // 以上配置原则:如果原大小为0,那么则配置1(个元素大小)   
  25.     // 如果原大小不为0,那么配置原大小的2倍   
  26.     // 前半段用来放置原数据,后半段用来放置新数据   
  27.   
  28.     iterator new_start = data_allocator::allocate(len); // 实际配置   
  29.     iterator new_finish = new_start;  
  30.     __STL_TRY {  
  31.       // 复制   
  32.       new_finish = uninitialized_copy(start, position, new_start);  
  33.       construct(new_finish, x);  
  34.       ++new_finish;  
  35.       // 将安插点的原内容页拷贝过来(该函数也可能被insert(p,x)调用)   
  36.       new_finish = uninitialized_copy(position, finish, new_finish);  
  37.     }  
  38.     catch(...) {  
  39.       // "commit or rollback"(如果不成功那么一个都不留)   
  40.       destroy(new_start, new_finish);   
  41.       data_allocator::deallocate(new_start, len);  
  42.       throw;  
  43.     }  
  44.   
  45.     // 解构并释放原vector   
  46.     destroy(begin(), end());  
  47.     deallocate();  
  48.   
  49.     // 调整迭代器,指向新vector   
  50.     start = new_start;  
  51.     finish = new_finish;  
  52.     end_of_storage = new_start + len;  
  53.   }  
  54. }  
void push_back(const T& x) {    if (finish != end_of_storage) {  // 还有备用空间      construct(finish, x);   		// 直接在备用空间中构建元素      ++finish;                          	// 调整范围    }    else                                  // 已无备用空间      insert_aux(end(), x);			  }template 
void vector
::insert_aux(iterator position, const T& x) { if (finish != end_of_storage) { // 还有备用空间 // 在备用空间起始处构造一个元素,并以vector最后一个元素值为其初值 construct(finish, *(finish - 1)); ++finish; // 以下做啥用? T x_copy = x; copy_backward(position, finish - 2, finish - 1); *position = x_copy; } else { // 已無備用空間 const size_type old_size = size();//此时的size()等同于capacity() const size_type len = old_size != 0 ? 2 * old_size : 1; // 以上配置原则:如果原大小为0,那么则配置1(个元素大小) // 如果原大小不为0,那么配置原大小的2倍 // 前半段用来放置原数据,后半段用来放置新数据 iterator new_start = data_allocator::allocate(len); // 实际配置 iterator new_finish = new_start; __STL_TRY { // 复制 new_finish = uninitialized_copy(start, position, new_start); construct(new_finish, x); ++new_finish; // 将安插点的原内容页拷贝过来(该函数也可能被insert(p,x)调用) new_finish = uninitialized_copy(position, finish, new_finish); } catch(...) { // "commit or rollback"(如果不成功那么一个都不留) destroy(new_start, new_finish); data_allocator::deallocate(new_start, len); throw; } // 解构并释放原vector destroy(begin(), end()); deallocate(); // 调整迭代器,指向新vector start = new_start; finish = new_finish; end_of_storage = new_start + len; }}

 

        所谓的vector的大小的动态增长,并不是在原空间之后连续新空间(因为无法保证原空间之后尚有可供配置的空间)。而是以原来大小的两倍另外配置一块较大空间,然后将原内容拷贝过来,然后才开始在原内容之后构造新元素,并释放原空间。因此,对vector的任何操作一旦引起重新配置,指向原vector的所有迭代器就都失效了。这就是为什么《C++ Primer》中说push_back和inser可能会使迭代器失效的原因。其本质是:空间已进行重新配置。

转载地址:http://ykafb.baihongyu.com/

你可能感兴趣的文章
谈谈编程思想
查看>>
iOS MapKit导航及地理转码辅助类
查看>>
检测iOS的网络可用性并打开网络设置
查看>>
简单封装FMDB操作sqlite的模板
查看>>
iOS开发中Instruments的用法
查看>>
强引用 软引用 弱引用 虚引用
查看>>
数据类型 java转换
查看>>
"NetworkError: 400 Bad Request - http://172.16.47.117:8088/rhip/**/####t/approval?date=976
查看>>
mybatis 根据 数据库表 自动生成 实体
查看>>
C结构体、C++结构体、C++类的区别
查看>>
进程和线程的概念、区别和联系
查看>>
CMake 入门实战
查看>>
绑定CPU逻辑核心的利器——taskset
查看>>
Linux下perf性能测试火焰图只显示函数地址不显示函数名的问题
查看>>
c结构体、c++结构体和c++类的区别以及错误纠正
查看>>
Linux下查看根目录各文件内存占用情况
查看>>
A星算法详解(个人认为最详细,最通俗易懂的一个版本)
查看>>
利用栈实现DFS
查看>>
(PAT 1019) General Palindromic Number (进制转换)
查看>>
(PAT 1073) Scientific Notation (字符串模拟题)
查看>>