使用vector和string时需注意的问题

栏目: 编程工具 · 发布时间: 8年前

内容简介:使用vector和string时需注意的问题

随着对STL的频繁使用和着迷,越发意识到更深层次理解STL的重要性。使用STL正确得到结果是一回事,而高效地使用STL得到结果又是另一回事。因此,拿起了Scott Meyers大神的《Effective STL》,结合自己平时遇到的问题,作一些总结和记录。

使用reserve避免不必要的重新分配

我们知道,STL容器最大的进步之一是它们会自动增长以便容纳下所放入的数据,只要没有超出它们的最大限制(可以使用max_size()成员函数查看)就可以。vector和string的增长过程是:

(1)分配一块大小为当前容量的某个倍数的新内存,在大多数实现中,vector和string的容量每次以2的倍数增长,即每当容器需要扩张时,它们的容量即加倍。

(2)把容器的所有元素从旧的内存复制到新的内存中。

(3)析构掉旧内存中的对象。

(4)释放旧内存。

可以看出,这个过程会非常耗时。因此,可以使用reserve成员函数来讲重新分配的次数减少到最低限度,从而避免了重新分配和迭代器/引用失效带来的开销。

因此,当一个元素需要被插入而容器的容量不够时,就会发生重新分配过程。比如:创建一个1到1000之间的vector ,如果采用这样的方式:

vector<int> ivec;
for(int i=1;i<=1000;i++)
    ivec.push_back(i);

对于大多数STL实现,该循环在进行过程中将导致2到10次重新分配。而如果改用reserve。

vector<int> v;
v.reserve(1000);
for(int i=1;i<=1000;++i)
    v.push_back(i);

那么,在循环过程中,将不会再发生重新分配。

所以,当能确切知道或大致预计容器中最终会有多少元素时,使用reserve。如果不知道,可以先预留足够大的空间,然后,当所有数据都加入以后,再去除多余的容量。

把vector和string数据传递给旧的C API

在使用C/C++时,我们发现很多时候还有旧的C API的身影,它们使用数组和char*指针而不是vector或string对象来进行数据交换。因此,在使用STL时,也必须处理好与旧的C API之间的关系。

比如,有一个vector v,而需要得到一个指向v中数据的指针,从而可把v中的数据作为数组来对待,那么只需要使用&v[0]就可以了。而对于string s,对应的形式是s.c_str()。

所以,对于给定的C API:

void doSomething(const int* pInts, size_t numInts);

可以这样使用:

if(!v.empty()){
    doSomething(&v[0], v.size());
}

请注意,不要使用v.begin()来代替&v[0],因为begin的返回值是一个迭代器,不是指针;当需要一个指向vector中的数据的指针时,永远不应该使用begin()。(可以使用&*v.begin())

但是,上述方法对string却是不可靠的。原因如下:

(1)string中的数据不一定存储在连续的内存中;

(2)string的内部表示不一定是以空字符结尾的。

所以,对于给定的C API:

void doSomething(const char* pString)

可以这样使用:

doSomething(s.c_str())

避免使用vector

作为一个STL容器,vector

有两点问题。首先,它不是一个STL容器。其次,它并不存储bool。除此之外,一切正常。

vector 不是一个STL容器,原因是一个对象要成为STL容器,必须满足的一个条件是,支持operator[]。也就是当使用operator[]取得了容器Container

中的一个T对象,那么可以通过取它的地址得到一个指向该对象的指针。

因此,如果vector 是一个容器,那么下面这段代码必须可以被编译:

vector<bool> v;
bool *p = &v[0];
但是,它不能通过编译。原因是,vector 是一个假的容器,它并不真的储存bool,相反,为了节省空间,它储存的是bool的紧凑表示。在一个典型的实现中,储存在”vector”中的每个”bool”仅占一个二进制位,一个8位的字节可容纳8个”bool”。在内部,vector

使用了与位域一样的思想,来表示它所存储的那些bool;实际上它只是假装存储了这些bool。

位域与bool相似,它只能表示两个可能的值,但是在bool与看似bool的位域之间有一个重要的区别:可以创建一个指向bool的指针,而指向单个位的指针则是不允许的。

所以,在上述的实验中,vector

::operator[]需要返回一个指向单个位的引用,而这样的引用却不存在。

那么。当需要vector

的时候,应该使用什么呢?

标准库提供了两种选择,可以满足绝大多数的需求。第一种是deque 。deque几乎提供了vector所提供的一切,而deque 是一个STL容器,并且确实存储bool。只是需要注意的是,deque中的元素的内存不是连续的,所以不能把deque

中的数据传递给一个期望bool数组的C API。

第二种方案时bitset。bitset不是STL容器,但它是标准C++库的一部分。与STL容器不同的是,它的大小(即元素的个数)在编译时就确定了,所以它不支持插入和删除元素。而且,它不支持迭代器。但是,与vector 一样,它使用了一种紧凑表示,只为包含所包含的每个值提高一位空间,它提供了vector 所特有的flip成员函数,以及其他一些特有的、对位的集合有意义的成员函数。在不需要迭代器和动态改变大小的环境下,bitset很适合需要。

string实现的多样性

几乎每个string实现都包含如下信息:

(1)字符串的大小,即所包含的字符的个数。

(2)用于存储该字符串中字符的内存的容量。

(3)字符串的值。

除此之外,一个string可能还包含:

(1)它的分配子的一份拷贝。

(2)对值的引用计数。

不同的string实现以不同的方式来组织这些信息。下面以4种不同的string实现方式来说明。它们来源于四种STL实现。

实现A

每个string对象包含其分配子的一份拷贝、该字符串的大小、它的容量以及一个指针,该指针指向一块动态分配的内存,其中包含了引用计数和字符串的值。

使用vector和string时需注意的问题

在该实现中,使用默认分配子的string对象是一个指针的4倍。若使用了自定义的分配子,则string对象会更大一些,多出的部分取决于分配子对象的大小。

实现B

在实现B中,string对象与指针大小相同,因为它只包含一个指向结构的指针。B的string所指向的对象中包含了该字符串的大小、容量和引用计数,以及一个指向动态分配的内存的指针,该内存中存放了字符串的值。

使用vector和string时需注意的问题

实现C

在实现C中,string对象的大小总是与指针的相同,该指针指向一块动态分配的内存,其中包含了与该字符串相关的一切数据:它的大小、容量、引用计数和值。

使用vector和string时需注意的问题

实现D

实现D的string对象是指针大小的7倍(仍然假定使用的是默认的分配子)。这一实现不使用引用计数,但是每个string对象内部包含一块内存,最大可容纳15个字符的字符串。因此,小的字符串可以完整地存放在string对象中,这通常被称为“小字符串优化”特性。而当一个string的容量超过15时,该内存的起始部分被当做一个指向一块动态分配的内存的指针,而该string的值就在这块内存中。

使用vector和string时需注意的问题

比较

(1)在以引用计数为基础的设计方案中,string对象之外的一切可以被多个string对象(如果它们有同样的值)。所以,实现A比实现B或C提供了较小的共享能力。尤其是,实现B和C可以共享string的大小和容量,从而减少每个对象存储这些数据的平均开销。

(2)创建一个新的字符串值可能需要零次、一次或两次动态分配。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Algorithms to Live By

Algorithms to Live By

Brian Christian、Tom Griffiths / Henry Holt and Co. / 2016-4-19 / USD 30.00

A fascinating exploration of how insights from computer algorithms can be applied to our everyday lives, helping to solve common decision-making problems and illuminate the workings of the human mind ......一起来看看 《Algorithms to Live By》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

随机密码生成器
随机密码生成器

多种字符组合密码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具