Part2:vector和string(一)

  • Rule13:尽量使用vector和string来代替动态分配的数组
    如果使用new来进行动态分配,你需要考虑如下事实:
    1. 你必须确保有的人以后会delete这个分配。如果后面没有delete,你的new就会产生一个资源泄漏。
    2. 你必须确保使用了delete的正确形式。对于分配一个单独的对象,必须使用“delete”。对于分配一个数组,必须使用“delete []”。如果使用了delete的错误形式,结果会未定义。在一些平台上,程序在运行期会当掉。另一方面,它会默默地走向错误,有时候会造成资源泄漏,一些内存也随之而去。
    3. 你必须确保只delete一次。如果一个分配被删除了不止一次,结果也会未定义。

如果你准备动手分配一个数组,也就是企图写new T[]。你应该首先考虑使用一个vector或一个string。vector和string消除了上面的负担,因为他们管理自己的内存。当元素添加到那些容器中时他们的内存会增加,而且当一个vector或string销毁时,他的析构函数会自动销毁容器中的元素,回收存放那些元素的内存。

Rule14:使用reserve来避免不必要的重新分配
reserve成员函数允许你最小化必须进行的重新分配的次数,因为可以避免真分配的开销和迭代器/指针/引用失效。

vector 的reserve增加了vector的capacity,但是它的size没有改变!而resize改变了vector的capacity同时也增加了它的size!
原因如下:
reserve是容器预留空间,但在空间内不真正创建元素对象,所以在没有添加新的对象之前,不能引用容器内的元素。加入新的元素时,要调用push_back()/insert()函数。
resize是改变容器的大小,且在创建对象,因此,调用这个函数之后,就可以引用容器内的对象了,因此当加入新的元素时,用operator[]操作符,或者用迭代器来引用元素对象。此时再调用push_back()函数,是加在这个新的空间后面的。
两个函数的参数形式也有区别的,reserve函数之后一个参数,即需要预留的容器的空间;resize函数可以有两个参数,第一个参数是容器新的大小, 第二个参数是要加入容器中的新元素,如果这个参数被省略,那么就调用元素对象的默认构造函数。

Rule16:如何将vector和string的数据传给遗留的C API
如果已经存在一个遗留的C风格API接收的是数组和char*指针,而不是vector和string对象。如果你有一个vector对象v,而你需要得到一个指向v中数据的指针,以使得他可以被当做一个数组,只要使用&v[0]就可以了。而对于string对象s,相应的是使用s.c_str()。
如如下代码示例:

void doSomething(const int* pInts,size_t numInts)
{
    for (int i =0;i<numInts;i++)
    {
        cout<<pInts[i]<<endl;
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
    vector<int> vec;
    vec.push_back(1);
    vec.push_back(2);
    vec.push_back(3);
    vec.push_back(4);
    doSomething(&vec[0],vec.size());
    getchar();
    return 0;
}

如果v是空的。如果这样的话,v.size()是0,而&v[0]试图产生一个指向根本就不存在的东西的指针。所以安全的代码是需要在前面进行一次 判断

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

Rule17:使用“交换技巧”来修整过量容器
vector的容量增加后不会自动变小,即使实际容量很小了。要避免你的vector持有它不需要的内存,需要有一种方法把他从曾经最大的容量减少到他需要的容量。
使用方法如下:
vector< type>(val).swap(val);
我们分析代码的意思:
表达式vector< type>(val)建立一个临时vector,他是val的一份拷贝:vector的拷贝构造函数做了这个工作。但是,vector的拷贝构造函数只分配拷贝的元素需要的内存。所有这个临时vector没有多余的容量。然后我们让临时vector和val交换数据,这时val只有临时变量的修整过的容器,这个临时变量则持有曾经的过多的容量。在这个语句结尾后,临时vector被销毁,释放以前val使用的内存。

交换技巧的变体可以用于清除容器。
string s;

vector< type>().swap(v); // 清除v而且最小化它的容量
string().swap(s);

Rule18:避免使用vector< bool >
因为作为一个STL容器,vector< bool >确实只有两个问题。第一,它不是一个STL容器。第二,他并不容纳bool。
一个东西要成为STL容器需要支持operator[]操作。那么以下代码必须能够编译

T *p = &c[0];
但是对于vector< bool > v; bool *pb = &v[0];用vector< bool >::operator[]返回的东西的地址初始化一个 bool*。
    vector<bool> v;
    bool *pb = &v[0];   
    这段话在vs中直接通不过编译  

当然除此之外,vector< bool >和其他类型的容器使用一样。

标准库提供了两个替代品,它们能满足几乎所有需要。第一个是deque< bool>。deque提供了几乎所有vector所提供的(唯一值得注意的是reserve和capacity),而deque< bool >是一个STL容器,它保存真正的bool值。当然,deque内部内存不是连续的。

第二个vector< bool >的替代品是bitset。bitset不是一个STL容器,但它是C++标准库的一部分。与STL容器不同,它的大小(元素数量)在编译期固定,因此它不支持插入和删除元素。此外,因为它不是一个STL容器,它也不支持iterator。但就像vector,它使用一个压缩的表示法,使得它包含的每个值只占用一比特。它提供vector特有的flip成员函数,还有一系列其他操作位集(collection of bits)所特有的成员函数。如果不在乎没有迭代器和动态改变大小,你也许会发现bitset正合你意。
bitset需要的命名空间:

#include <bitset>
using std::bitset;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值