【问题标题】:What is best to insert several values at the end of a std::vector?在 std::vector 的末尾插入几个值最好是什么?
【发布时间】:2022-01-10 14:10:11
【问题描述】:

将元素添加到std::vector<int> v 是不是更好:

// Read and manipulate a, b, c triplet as ints.
// Potentially also: v.reserve(v.size() + 3); or trust vector growth policy?
v.push_back(a);
v.push_back(b);
v.push_back(c);

v.insert(v.end(), {a, b, c});

从性能的角度来看(假设我们总是要插入每次都不同的三元组以及大量不固定数量的三元组,比如 100 万个三元组)?感谢您的提示。

【问题讨论】:

    标签: c++ performance vector insert c++20


    【解决方案1】:

    首先,在循环中执行v.reserve(v.size() + 3); 通常是一个非常糟糕的主意,因为它肯定会导致每次迭代都有新的重新分配。例如,带有 libstdc++ 和 libc++ 的 Clang 和 GCC 实际上都会进行线性数量的重新分配(请参阅 herehere 甚至 there)。这是cppreference的引述:

    正确使用reserve()可以防止不必要的重新分配,但不恰当地使用reserve()(例如,在每次push_back()调用之前调用它)实际上可能会增加重新分配的数量(通过导致容量增长线性而不是指数)并导致计算复杂度增加和性能下降。例如,通过引用接收任意向量并向其附加元素的函数通常不应在向量上调用 reserve(),因为它不知道向量的使用特性。
    插入范围时,insert() 的范围版本通常更可取,因为它保留了正确的容量增长行为,这与 Reserve() 后跟一系列 push_back() 不同。
    reserve() 不能用来减少容器的容量;为此,提供了 shrink_to_fit()。

    当谈到insert VS push_backs 时,insert 应该比许多push_back 稍微好一点,因为容量检查只能进行一次而不是多次push_backs。话虽如此,性能差异很大程度上取决于标准库的实现。

    【讨论】:

    • 但是可以肯定地说std::initializer_list<int> 版本{a, b, c} 被优化了吗?
    • 可能不会。实际上,Clang 似乎没有优化这有点令人惊讶(它为 push_back 和插入生成了一个非常糟糕的代码)。话虽如此,与在std::vector<int> 中插入大量值的成本相比,复制少量整数(通常在 L1 缓存中)的成本可以忽略不计:最大的开销来自内存层次结构(L3-缓存/RAM,当然还有页面错误)。
    • 感谢您的详细解答!
    猜你喜欢
    • 2019-12-22
    • 2016-03-30
    • 2011-01-13
    • 1970-01-01
    • 2015-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-18
    相关资源
    最近更新 更多