正确的方法是将矢量"保留或缩小"到已知的未来容量需求

use*_*284 5 c++ stdvector

我已经围绕长寿命向量的共同主题编写了无数的软件模块,有时(在未指定的频率下)必须更新其内容.

惯用法实施:

void LongLived::reconfigure(const InputT& whatever_input)
{
    m_vector.clear();

    m_vector.reserve(whatever_input.size());

    populate(m_vector, whatever_input);
}
Run Code Online (Sandbox Code Playgroud)

请注意,惯用实现永远不会减少其内部缓冲区的容量.如果这不好怎么办?只是用shrink_to_fit(),我想:

void LongLived::reconfigure(const InputT& whatever_input)
{
    m_vector.clear();

    m_vector.reserve(whatever_input.size());
    m_vector.shrink_to_fit(whatever_input.size()); // ? Here

    populate(m_vector, whatever_input);
}
Run Code Online (Sandbox Code Playgroud)

哦,那将是多么美好......但令我惊讶的是,它没有编译,因为shrink_to_fit()不需要一个数字!

shrink_to_fit()应该使用的方式显然是先填充向量.然后,你调用shrink_to_fit(),这将从事后的向量中的元素数量中获得容量需求,但如果我事先已经告诉它,那显然是次优的,因为现在,所有内容都必须被移动.

目标:我想vector_reserve_or_shrink()在这种情况下使用一个函数:

void LongLived::reconfigure(const InputT& whatever_input)
{
    m_vector.clear();

    vector_reserve_or_shrink(m_vector, whatever_input.size()); // ? Implement this!

    populate(m_vector, whatever_input);
}
Run Code Online (Sandbox Code Playgroud)

我实际上并不痴迷于从矢量中删除每个未使用的字节.更确切地说,我很乐意将其留给某些实现定义,例如shrink_to_fit(),可能知道分配器的怪癖,并可能选择什么都不做.通过这种方式,人们不会冒险进行抽象反转,从而否定任何较低级别的优化.例如,假设分配器的粒度是16:那么,当你要求一个时,矢量实现可能会免费给你15个字节,据我所知,这对于尝试回馈只会适得其反.

gez*_*eza 4

使用这样的东西:

template <typename VECTOR>
void setCapacity(VECTOR &vector, std::size_t capacity) {
    if (capacity < vector.size()) capacity = vector.size();
    if (vector.capacity() > capacity) {
        VECTOR v;
        v.reserve(capacity);
        std::size_t size = vector.size();
        for (std::size_t i = 0; i < size; i++) {
            v.emplace_back(std::move(vector[i]));
        }
        vector.swap(v);
    } else {
        vector.reserve(capacity);
    }
}
Run Code Online (Sandbox Code Playgroud)

它将向量容量设置为capacity(如果可能),同时保留元素。而且它只进行一次分配。