Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1347139
  • 博文数量: 244
  • 博客积分: 1039
  • 博客等级: 少尉
  • 技术积分: 1562
  • 用 户 组: 普通用户
  • 注册时间: 2011-01-06 09:40
文章分类

全部博文(244)

文章存档

2021年(2)

2019年(6)

2018年(2)

2014年(1)

2013年(187)

2012年(47)

分类: C/C++

2012-03-19 21:42:30

        STL vector 比较神奇的地方,就是它会自动的扩展自己的容量。而这些是在 C/C++ 的低级数据结构——数组里面是办不到的。

 

合适的扩张:

         譬如,在 C++ 中,有如下的代码:

         const int kSize = 10;

         int ar[kSize];

 

         数组 ar 的大小是在编译期间完成,它的内容是存在内存中的栈里面。顺便提一下,在 c c++ 中,由编译器分配的内存是分配在栈( Stack )里面,而由程序员分配管理的内存是在堆( heap )里面。

 

         数组就是相同类型的一种集合的其中一种表现形式。它具有快速,简单的特点。但是想进一步的扩展是比较困难的。譬如我想把上面的数组的大小改为 11 ,那明显是很难办到的。 STL 中的 vector 可以帮你解决这个问题。

 

         譬如,在 C++ 中的下面的代码:

         const  int  kSize = 10;

         vector iv;

         for (int i = 0; i < kSize; ++i)  {

         iv.push_back(i);

}

那么容器 iv 中有是kSize个元素,同时,这个时候,我想在这个容器加进去一个元素,是非常方便的。譬如,我想加一个 int a = 100 的数进来, iv.push_back(a); 就行了。

 

 

是的,上面的代码确实是比较好,比数组灵活很多。但绝对不是最好的。这涉及到 vector 的内存分配机制。

先看 vector 的几个成员函数:

size ():这个函数是获得 vector 容器有多少个元素。

capacity ():这个函数获得 vector 容器还能在内存中可以容纳多少元素。(不会导致内存重新分配,下面会讲解这个)。

resize () : 强行把 vector 的元素个数扩展或者是减少到所指定的元素。

reserve ():把容器的容量置为所指定的元素。

 

vector 的内存分配机制:当向其插进元素,而超过它的容量的时候,它会以一种哲学的方式配置自己的容量。

什么是哲学的方式呢?按照上面的代码,当你想 iv 容器插入一个元素的时候,它可能分配 1 个大小的内存,也可能分配 2 个大小的内存,也可能分配 3 个大小的内存……在 GNU g++ 中,它会以原来 2 倍的内存大小增加(请参考《 STL 源码剖析》)

同时,会进行一次的内存“搬移”,譬如假设上面已经有 5 个元素,他的容量也为 5 ,再向 vector 插入一个元素,这样会发生以下的动作:

1、  它必须重新分配适当的新的内存空间。

2、  把原来的数据“ copy ”过到新的空间,再插入一个元素。

3、  销毁原来的数据。

这是一个非常耗时的过程。

然而这个问题是怎么解决,不至于有这么多好耗时的动作呢? reserve ()成员函数。把上面的代码改为:

         const  int  kSize = 10;

         vector iv;

         iv.reserve(kSize);

         for (int i = 0; i < kSize; ++i)  {

         iv.push_back(i);

 }

只是在 vector 在分配内存的机制上面,预先保留,就可以减少:

1、  内存重新分配。

2、  内存“数据搬移”

3、  销毁原来的数据

三个动作。

 

合适的收缩:

         问题的引进:现在容器 vector 存贮着 100000 人的数据,而我们只是根据某种质量,把关注点放在前十位。譬如:在这些人中,选出 10 个是长得最高的(只是需要简单的 sort 就行),其他的 99990 人都不关心,所以想从内存中删除。

代码 :

class Person {

         ……

}

vector ip;

……

 

在删除 vector 的元素,一般采用 erase-remove 的方法,但是这个方法只能是减少元素,并不能减少容器本身所占用的内存空间。咋办?比你想象的更加简单,只是需要一句话:

vector(ip).swap(ip);

 

当你打印出 ip.capacity() 的前后的值,就发现完全是不同的。

 

 

string 可以采用和 vector 基本相同的方式来管理合适的内存,不会导致内存的多次分配造成的无谓的消耗,也不会导致内存的过大,导致内存的浪费。

 

在合适的收缩内存这一点上,不一定采用 vector ,或者是 map 处理更加好, map 是采用红黑二叉树的方式写成,可以按照某种质量自动排序,获取前 10 位。

 

请参考《 C++ primer 》,《 Effective C++ 》,《 Effective STL 》,《 STL 源码剖析》

阅读(1388) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~