std::vector<T>的reserve()和resize()
预备概念:容器:有效元素的存储空间,不包括多余容量;容量:是为了减少哪些使用连续空间(线性空间)存储元素的容器在增加元素时重新分配内存的次数的一种限制,即当增加元素且剩余空间不足时,按照一定比例多分配出一些空闲空间以备将来再增加元素时使用。多余出来的容量是未经初始化的(注意:并没有调用元素类型的默认构造函数来初始化)。有效元素:调用元素类型的默认构造函数初始化过的存储空间。std:
预备概念:
容器:有效元素的存储空间,不包括多余容量;
容量:是为了减少哪些使用连续空间(线性空间)存储元素的容器在增加元素时重新分配内存的次数的一种限制,即当增加元素且剩余空间不足时,按照一定比例多分配出一些空闲空间以备将来再增加元素时使用。多余出来的容量是未经初始化的(注意:并没有调用元素类型的默认构造函数来初始化)。
有效元素:调用元素类型的默认构造函数初始化过的存储空间。
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之后(图一)和拷贝后结构图(图二)如下:
更多推荐
所有评论(0)