为什么fill_n()不能与vector.reserve()一起使用?

4

我最近正在学习标准库算法,对于函数fill_n(iter, n, val)有一个问题。这个函数要求容器从iter开始至少有n个元素。

这是测试代码:

// Version 1, Error
vector<int> vec;
vec.reserve(10);  // Only allocate space for at least 10 elements
fill_n(vec.begin(), 10, 0);

// Version 2, OK
vector<int> vec;
vec.resize(10);  // Value initialized 10 elements
fill_n(vec.begin(), 10, 0);

// Version 3, OK
vector<int> vec;
fill_n(back_inserter(vec), 10, 0);  // Push back 10 elements via back_inserter

为什么版本1的代码出错,而版本2和3没有出错?
3个回答

4

reserve 只是保留了空间,但 vector 的大小仍然不变。由 begin 返回的迭代器无法超出 vector 的末尾,因为它是(未更改的)大小决定了 vector 的末尾位置,所以你会得到一个错误。


4

版本1无法工作,因为:

std::reserve修改的是向量的容量而不是其大小。 std::fill_n要求容器事先具有正确的大小

版本2可行,因为:

std::resize确实修改了向量的大小,而不仅仅是它的容量。

版本3可行,因为:

std::back_inserter将调用向量上的push_back,从而添加到向量并相应地修改其大小。


2

reserve并不会初始化任何内容,它只是预留一些空间,以便每次推入新项目时都不会发生重新分配。

因此,解决方案是告诉fill_n将其结果直接推送到vector的末尾。

更改如下:

// Version 1, Error
vector<int> vec;
vec.reserve(10);  // Only allocate space for at least 10 elements
fill_n(vec.begin(), 10, 0);

To:

// Version 1, Corrected
vector<int> vec;
vec.reserve(10);  // Only allocate space for at least 10 elements
fill_n(std::back_inserter(vec), 10, 0);

2
我喜欢这个回答,但我认为应该有更明确的评论,即当使用更正后的版本时,back_inserter不会因为前面语句中的reserve调用而导致重新分配。当然,对于vec的任何进一步插入、push_back等操作可能会导致重新分配。 - Andre Kostur

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接