调整大小并在向量中保留
resize and reserve in vector
主要问题
即使向量的容量大于其大小,resize
是否会影响性能?
比如我想做一个伪代码如下
const size_t size_a = 2;
const size_t i_max = 3;
vector<int> a(size_a) = random_vector;
vector<int> b;
for (size_t i=0; i<i_max; i++){
patch_a_at_the_end_of_b;
}
所以,b
每次循环都会改变它的大小,但它会单调增加,我知道 b
的最终大小。
首先,我创建了一个函数 concat(a,b)
,以便将 a
补丁到 b
的末尾。
void concat(const vector<int> a, vector<int> &b){
const size_t size_b = b.size();
b.resize(size_b+a.size());
for(size_t i=0; i<a.size(); i++)
b[size_b + i] = a[i];
}
请注意,每次 concat
调用 b
时,我们都会调整向量的大小。
然后,我在主函数的for
循环前面添加b.reserve
。
const size_t size_a = 2;
const size_t i_max = 3;
vector<int> a(size_a) = random_vector;
vector<int> b;
b.reserve(size_a*i_max);
for (size_t i=0; i<i_max; i++){
concat(a,b);
}
std::vector
s 操作的规范可能提供了这个问题的大部分答案。
首先,resize()
被指定为void resize(size_type n, value_type val = value_type())
,有要求;
- 如果
n
小于当前大小,则移除并销毁附加元素(即,如果元素具有析构函数,则调用析构函数)。
- 如果
n
大于当前容器大小,则通过在末尾插入所需数量的元素来扩展内容以达到 n
的大小。如果指定 val
,则新元素被初始化为 val
的副本,否则,它们被值初始化。
- 如果
n
也大于(强调我的)比当前容器容量,分配的自动重新分配存储 space 发生。
请注意,如果减小容器的大小,则不会减少容器容量。
现在,reserve(size_type n)
被指定为要求向量容量为n
个或更多元素,要求
- 如果 n 大于当前向量容量,则函数导致
容器重新分配其存储,将其容量增加到 n
(或更大)。
- 在所有其他情况下,函数调用不会导致重新分配,向量容量也不会受到影响。
- 此函数对向量没有影响
size
并且不能改变它的元素。
这里的第二点可以理解为说reserve()
不能用来减容
注:我在上面转述了,但它本质上是对resize()
和reserve()
标准要求的总结。
将这些点放在一起:唯一需要resize()
(或任何其他增加向量大小的操作)来增加向量容量的情况是新大小超过当前容量.
除此之外,发生的是实施质量问题。但是,一种合乎逻辑的实施方式是;
resize()
(以及其他增加向量大小的操作)永远不会增加容量,除非新大小超过当前容量
reserve()
从不减少容量
在这样的实现中,在执行增加向量大小的操作之前调用 reserve()
会带来性能优势(消除实际重新分配的需要,除非大小增长到超过使用 [=22 指定的容量) =]).
如果实现使用不同的方法,例如在任何阶段减少容器的容量(例如,如果调用 resize()
减少大小,它也会减少容量),情况可能会有所不同。这样做可能是为了尽量减少容器的总内存使用量(即,只要 vector
本身存在,就不会保留分配的额外容量)。如果向量的大小波动(例如,在某些情况下增加,在其他情况下减少),这将对性能产生影响。
主要问题
即使向量的容量大于其大小,resize
是否会影响性能?
比如我想做一个伪代码如下
const size_t size_a = 2;
const size_t i_max = 3;
vector<int> a(size_a) = random_vector;
vector<int> b;
for (size_t i=0; i<i_max; i++){
patch_a_at_the_end_of_b;
}
所以,b
每次循环都会改变它的大小,但它会单调增加,我知道 b
的最终大小。
首先,我创建了一个函数 concat(a,b)
,以便将 a
补丁到 b
的末尾。
void concat(const vector<int> a, vector<int> &b){
const size_t size_b = b.size();
b.resize(size_b+a.size());
for(size_t i=0; i<a.size(); i++)
b[size_b + i] = a[i];
}
请注意,每次 concat
调用 b
时,我们都会调整向量的大小。
然后,我在主函数的for
循环前面添加b.reserve
。
const size_t size_a = 2;
const size_t i_max = 3;
vector<int> a(size_a) = random_vector;
vector<int> b;
b.reserve(size_a*i_max);
for (size_t i=0; i<i_max; i++){
concat(a,b);
}
std::vector
s 操作的规范可能提供了这个问题的大部分答案。
首先,resize()
被指定为void resize(size_type n, value_type val = value_type())
,有要求;
- 如果
n
小于当前大小,则移除并销毁附加元素(即,如果元素具有析构函数,则调用析构函数)。 - 如果
n
大于当前容器大小,则通过在末尾插入所需数量的元素来扩展内容以达到n
的大小。如果指定val
,则新元素被初始化为val
的副本,否则,它们被值初始化。 - 如果
n
也大于(强调我的)比当前容器容量,分配的自动重新分配存储 space 发生。
请注意,如果减小容器的大小,则不会减少容器容量。
现在,reserve(size_type n)
被指定为要求向量容量为n
个或更多元素,要求
- 如果 n 大于当前向量容量,则函数导致 容器重新分配其存储,将其容量增加到 n (或更大)。
- 在所有其他情况下,函数调用不会导致重新分配,向量容量也不会受到影响。
- 此函数对向量没有影响
size
并且不能改变它的元素。
这里的第二点可以理解为说reserve()
不能用来减容
注:我在上面转述了,但它本质上是对resize()
和reserve()
标准要求的总结。
将这些点放在一起:唯一需要resize()
(或任何其他增加向量大小的操作)来增加向量容量的情况是新大小超过当前容量.
除此之外,发生的是实施质量问题。但是,一种合乎逻辑的实施方式是;
resize()
(以及其他增加向量大小的操作)永远不会增加容量,除非新大小超过当前容量reserve()
从不减少容量
在这样的实现中,在执行增加向量大小的操作之前调用 reserve()
会带来性能优势(消除实际重新分配的需要,除非大小增长到超过使用 [=22 指定的容量) =]).
如果实现使用不同的方法,例如在任何阶段减少容器的容量(例如,如果调用 resize()
减少大小,它也会减少容量),情况可能会有所不同。这样做可能是为了尽量减少容器的总内存使用量(即,只要 vector
本身存在,就不会保留分配的额外容量)。如果向量的大小波动(例如,在某些情况下增加,在其他情况下减少),这将对性能产生影响。