【问题标题】:How to clear a vector but keeping its capacity? [duplicate]如何清除向量但保持其容量? [复制]
【发布时间】:2016-08-29 21:19:05
【问题描述】:

我正在尝试修复一些大量使用向量的代码,并且有些循环看起来像这样:

for (int t=0;t<T;t++){    
    std::vector<double> vect;
    for (int i=0;i<MAX;i++){
        double value;
        vect.push_back(value);
    }
    /*....*/
}

我或多或少知道如何通过在外部迭代中重用相同的向量来改进这一点,但是在这样做时我发现在调用std::vector::clear"the vector capacity is not guaranteed to change" 时,我实际上希望容量能够保证没变。也许我只是误解了 cplusplus.com 上写的内容。但是,我的问题是:

如何在不改变容量的情况下清除矢量?

我应该在clear 之后调用reserve 以确保容量相同吗?

PS:为了清楚起见,我想将上面的代码重写为

std::vector<double> vect;
vect.reserve(MAX);
for (int t=0;t<T;t++){    
    for (int i=0;i<MAX;i++){
        double value;
        vect.push_back(value);
    }
    /*....*/
    vect.clear();
}

即。我仍然想通过push_back 填充它,我担心clear() 会改变向量的容量。

【问题讨论】:

  • 这里有相关的讨论。共识似乎是调整向量 SMALLER 的大小不得影响容量。 stackoverflow.com/questions/1624803/…
  • 更好的答案是stackoverflow.com/a/18467916
  • @Cubbi 在阅读了该答案之后的讨论后,我非常确信 clear 不允许更改容量,因此我的问题有点过时(并且 cplusplus 在这一点上似乎是错误的)。我的教训是:永远不要相信除了标准之外的任何人;)

标签: c++ vector


【解决方案1】:

cppreference明确表示向量的容量不变。

来自 cppreference(粗体强调它是我自己的):

void clear();

从容器中移除所有元素。使任何引用无效, 指向包含元素的指针或迭代器。可能无效 任何过去的迭代器。
保持向量的容量()不变。

编辑

正如 Dmitry Kuznetsov 在评论中指出的那样,standard 没有提到容量:

表达式: a.clear()

返回类型: void
断言/注意前置/后置条件: 销毁 a 中的所有元素。使所有引用的引用、指针和迭代器无效 a 和的元素可能会使过去的迭代器无效。

post: a.empty() 返回 true。

复杂性:线性。

【讨论】:

  • hm 在这种情况下,标准所说的内容会很有趣,因为 cplusplus 声明这不能保证。
  • 这很可能只是 cplusplus 上的一个错字,而不是“不保证会改变”,实际上是指“保证不会改变”
  • 如有疑问,请参阅标准。无论如何,我不会关心 cplusplus 上写了什么。
  • 我认为这是正确的。此外,resize(0) 保证不会修改容量,根据 cppreference.com
  • 标准在别处说
【解决方案2】:

是的,在clear() 之后拨打reserve()。在最坏的情况下,您将进行一次解除分配/分配,这对 POD 向量的影响可以忽略不计。

【讨论】:

  • POD 没关系。当您调用 clear() 时,不会发生对象构造
【解决方案3】:

您可以存储从capacity() 返回的值并使用reserve() 方法。

不保证给你完全相同的capacity

将容器的容量增加到更大的值或 等于 new_cap。如果 new_cap 大于当前容量(), 分配新的存储空间,否则该方法什么也不做。

int main()
{
    vector<int> vec { 1,2,3,4,5 };
    size_t cap = vec.capacity(); 
    vec.clear();
    vec.reserve(cap);

    cout << "vec capacity: " << vec.capacity() << '\n';
}

【讨论】:

  • 你从哪里得到的报价?我特别感兴趣的是,如果请求的容量小于当前容量,是否真的保证什么都不做。并不是说它很重要,但有时细节确实很重要
  • 啊,谢谢,其实我有点困惑,因为在我的引文中我把 cppreference 和 cplusplus 混为一谈了...
【解决方案4】:

另一种方法是做一个交换技巧......

std::vector<double> vect = {0.1, 0.2, 0.3}
{
    std::vector<double> swapVector;
    swapVector.reserve(vect.capacity());
    vect.swap(swapVector); // swapVector now has the elements of vect
                           // vect has only reserved elements
} // swapVector will be destroyed (including the elements that was in vect)
std::cout << vect.capacity();

【讨论】:

  • "vect 超出范围时将被清除" ??我不明白
  • @tobi303 swapVector 在堆栈上创建,并已与 vect 中的元素交换。一旦函数超出范围,swapVector 将被销毁,它的元素......让我编辑我的答案
  • 我认为这种方法有很多缺点,没有优点。您正在强制释放和重新分配(尽管顺序不同),这正是 OP 想要避免的,
  • @Roddy 是的,我想你是对的。唯一的好处是(如果需要的话)是 vect 在元素被释放之前被“清空”......
【解决方案5】:

调用clear 将解除分配(不一定,但取决于实现),然后调用resize 将导致代价高昂的重新分配。显而易见的答案是遍历向量并将结果设置为0 / NULL

for(double& d : vect)
{
    d = 0;
    //d = NULL, depending on datatype
}

这只会“清除”向量,而无需进行昂贵的重新分配。当然,这个过程的性能很大程度上取决于元素的数量——这只是简单的出路。

【讨论】:

  • 我不想调整大小。边界条件是: 向量应该被清除,以便之后可以再次用push_back 填充到相同的容量。抱歉,如果这不清楚
  • 好吧。看来我误解了它;对不起。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-29
  • 2015-08-27
  • 1970-01-01
  • 2023-03-19
  • 1970-01-01
相关资源
最近更新 更多