设置*两个*元素和std :: vector的初始容量

时间:2014-07-20 00:53:42

标签: c++ c++11 vector

我在this post中读到std::vector的初始容量无法由其构造函数控制。设置它的最佳方法,如果你知道它的大小在运行时将保持不变,那么似乎是:

const int size;
std::vector<T> v;
v.reserve(size);

但是,由于T是一个大类,我很高兴使用构造函数std::vector<T> v(size, T());的初始化参数。那么只分配我需要的内存而不必手动迭代元素来初始化它们的最佳方法是什么?

std::vector<T> v;
v.reserve(size);
for(T t : v) t = T();    // `has to call T::operator= (that may not even be defined)

std::vector<T> v(size, T());  // may allocate more memory than I need..
v.shrink_to_fit();            // ..then deallocate it immediately (pointless)

最接近我理想的是什么:

std::vector<T> v(size, T(), /*capacity =*/ size);

[编辑]:根据您的回答,我需要更准确的是v填充sizeT个实例,每个版本都使用T默认构造函数,而不是复制。我怎么能这样做,因为在编译时不知道size时我无法使用初始化列表?


奖励:顺便说一句,为什么没有办法选择矢量的初始容量?

5 个答案:

答案 0 :(得分:5)

奖金优先:

  

奖励:顺便说一句,为什么没有办法选择矢量的初始容量?

因为班上的设计师从未认为它足够重要。


我知道之后没有实现:

std::vector<T> v(size, T());

以下断言不成立:

assert(v.capacity() == size);

标准不保证持有。但它确实似乎是事实上的标准。

然而,不能将这一部分知识转移到std::string


如果您希望在构建后积极要求capacity() == size(),则可以使用shrink_to_fit()。话虽如此,shrink_to_fit()并不能保证标准能够正常工作,如果它确实做了任何事情,它将暂时加倍你的内存需求。这种用法可能如下:

std::vector<T> v(size, T());
if (v.capacity() > v.size())
    v.shrink_to_fit(); // If executed and successful, this will allocate a new buffer
if (v.capacity() > v.size())
    // now what?

使用reserve()不再有效。在reserve()之后,如果重新分配,capacity() 更大或等于reserve的参数;并且等于capacity()之前的值。

答案 1 :(得分:2)

您不清楚如何构建所有元素。我们假设您希望向量具有n元素和容量desired_capacity,这可能等于n

如果您希望n元素相同,请尝试以下操作:

std::vector<T> v(n, t);  // creates n copies of the value t.
v.reserve(desired_capacity);

如果您不想指定初始值,可以省略:

std::vector<T> v(n);     // creates n copies of T, default constructed.
v.reserve(desired_capacity);

如果您要单独指定一定数量的元素,请尝试初始化列表。

std::vector({t1, t2, ..., tn});  // initializer list
v.reserve(desired_capacity);

可能性列表继续;有关更多信息,请参阅vector::vector reference。使用&#34;就地&#34;构造意味着您可以使用不可复制构造的类型填充向量。

使用不可复制类型填充向量的另一个选项是重复使用emplace_back:

std::vector<T> v;
v.reserve(n); 
for (int i = 0; i < n; ++i)
{
   v.emplace_back(x, y, z);  // Construct T(x, y, z) in-place
}

关于原始问题的一个注释:for循环包含错误:

for(T t : v) t = T();    
// almost certainly want for (T& t : v) ...
// in order to get references to modify vector elements.

答案 2 :(得分:1)

指定初始大小的向量构造函数都必须迭代才能初始化元素。即使您没有明确迭代初始化元素的代码,也就是向量构造函数中发生的事情。所以我没有看到做的问题:

template<typename T, typename... Args>
std::vector<T> create_vector_with_capacity(size_t size, size_t capacity, Args... args)
{
    std::vector<T> v;
    v.reserve(capacity);

    for (size_t i = 0; i != size; ++i)
        v.emplace_back( args... );

    return v;
}

样本用法:

std::vector<std::string> vec = create_vector_with_capacity<std::string>(5, 20, "foo");

std::vector移动语义确保即使禁用了copy-elision且T不可移动,也不会复制向量,即使它是按值返回的。

此版本使用args(或默认构造函数,如果您没有提供任何args)就地构建每个元素;或者,您可以将Args... argsemplace_back替换为T&& t = T()push_back,这将复制构建您传入的一个(可能是临时的)所有元素。

注意:实际上标准并不能绝对保证移动矢量会保留其容量(不管我是否意识到这一点);如果你的实现没有这样做,或者如果你真的想要保证容量保留,那么不要返回v,而是让它成为参考传递的参数,调用者必须为其提供空向量。

答案 3 :(得分:1)

您可以这样做:

std::vector<T> v;
v.reserve(size); // don't construct any T. v.size() == 0.
v.resize(size);  // do construct T.

答案 4 :(得分:-1)

你可以构建具有容量和初始值的向量,

std::vector<std::string> vs(5, "abc");
std::vector<std::pair<int, int>> x(6, std::pair<int,int>(1, 2));