预备概念:

容器:有效元素的存储空间,不包括多余容量;

容量:是为了减少哪些使用连续空间(线性空间)存储元素的容器在增加元素时重新分配内存的次数的一种限制,即当增加元素且剩余空间不足时,按照一定比例多分配出一些空闲空间以备将来再增加元素时使用。多余出来的容量是未经初始化的(注意:并没有调用元素类型的默认构造函数来初始化)。

有效元素:调用元素类型的默认构造函数初始化过的存储空间。

std::vector<T>的size()和capacity()这两个成员函数可以看出容器所辖有效元素空间和容量的区别:



void reserve(size_type n)成员函数:n是用户请求保留的总容量的大小;

reserve()的实现与作用:

(1)如果n大于容器现有的容量(即capacity()),则需要在自由内存区为整个容器重新分配一块新的更大的连续空间,其大小为n*sizeof(T),然后将容器内所有有效元素从旧位置全部拷贝到新位置(调用拷贝构造函数),最后释放旧位置的所有存储空间并调整容器对象的元素位置指示器。

(2)否则什么也不做


注意:除了调用容器的某些方法可以改变容器的大小外,在容器外部没有任何方法可以做到,示例如下:

//使用迭代器在冗余容量的空间上通过赋值来给容器增加元素

std::list<int> li;

std::vector<int> vi;

for(int c=0;c<10;c++)

    li.push_back(c);

vi.reserve(li.size());//预留空间,但是并没有改变容器的大小,预留空间未初始化

std::copy(li.begin(),li.end(),vi.begin());  //拷贝赋值

std::copy(vi.begin(),vi.end(),std::ostream_iterator<int>(std::cerr,"\t"));

上述程序错误:虽然vi.reserve()为vector预留了内存,但是改变的只是容器的容量。同时在copy()算法中对容器元素赋值也不会改变容器的大小,因此拷贝过后容器的size()仍然为0,虽然list的元素已经被拷贝到了vector预留空间上。结果:没有输出任何东西;vector在拷贝前后的状态变化如下图:



resize()的实现与作用

void resize(size_type n, const T&c = T());

n是最后要保留的元素个数,c是新增元素的默认初始值。

resize()的实现策略:

(1)如果n 大于容器当前的大小(即siez()),则在容器的末尾插入(追加)n-size()个初值为C的元素,如果不指定初值,则用元素类型的默认构造函数来初始化每一个新元素(可能引起内存重分配以及容器容量的扩张);

(2)如果n小于容器当前的大小,则从容器的末尾删除size() - n个元素,但不释放元素本身的内存空间,因此容量不变。

(3)否则什么也不做。

resize()和赋值操作及insert()、push_back()等都可以合作。

上例改写如下:

std::list<int> li;

std::vector<int> vi;

for(int c = 0;c < 10; c++){

    li.push_back(c);

}

vi.resize(li.size());  //调整容器大小

std::copy(li.begin(),li.end(),vi.begin());  //拷贝赋值

std::copy(vi.begin(),vi.end(),std::ostream_iterator<int>(std::cerr,"\t"));

//可以输出正确结果

resize之后(图一)和拷贝后结构图(图二)如下:







    





Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐