vector::reserve需要注意什么?

3

我试图做这样的事情:

#include <vector>
#include <algorithm>

int main()
{
    int l[] = {1,2,3,4};
    vector<int> vi(4);
    copy(l, l+4, vi.begin());

    do_stuff();
}

上述代码可以编译并且运行没有错误。然后我将其修改为以下代码:
int main()
{
    int l[] = {1,2,3,4};
    vector<int> vi;
    vi.reserve(4);  //different from the above code
    copy(l, l+4, vi.begin());

    do_stuff();
}

根据代码,我将vector<int> vi(4);改为vector<int> vi; vi.reserve(4);,但问题出现了,即更改后的代码可以编译,但运行时会出现段错误。

根据,段错误发生在函数do_stuff();中。

为什么会这样?我做的更改有关系吗?我不能在这里使用reserve吗?


你可能想调用 vi.resize(4),而不是 vi.reserve(4)。然而,就像你第一段代码中的情况一样,这会不必要地初始化向量为四个 0 元素。更好的方法是使用 reserve() 并使用 std::back_inserter 或立即使用正确的数据进行初始化。 - sbi
4个回答

9
reserve()方法仅分配内存,但不初始化。它只影响capacity(),而size()将保持不变。
如果您想创建尽可能多的实例,应使用resize(),它会分配内存,并创建与传递给resize()的参数相同数量的实例。

但是在这两种情况下,copy(...)之后vi.size()应该为4,对吗? - Alcott
3
如果你不相信Als说的“大小将保持不变”,那就测试一下吧。vector<int> vi; vi.reserve(4); std::cout << vi.size() << '\n';。它会输出0 - Steve Jessop
1
失败的代码创建了一个具有容量为四个元素的向量。成功的代码创建了一个具有四个元素的向量。 - David Schwartz
5
如果你想将“copy”插入到数组中,可以使用back_inserter(vi)作为目标迭代器。 - Mike Seymour
@PlasmaHH copy 怎么可能调整向量的大小?它甚至不知道向量的存在;它所看到的只是迭代器。 - James Kanze
显示剩余2条评论

3

我认为你想要实现的是使用一组元素初始化一个向量。在C++11中,可以通过新的列表初始化语法轻松实现:

std::vector<int> vi {1, 2, 3, 4};

如果你的编译器还不支持这种语法,你可以使用最基本的范围构造函数:
int a[] = {1, 2, 3, 4};
std::vector<int> vi(a + 0, a + 4);

如果出于某种原因,您确实想要预留空间,然后稍后再将元素推回,请按以下方式编写代码:

std::vector<int> vi;
vi.reserve(4);
int a[] = {1, 2, 3, 4};
std::copy(a + 0, a + 4, std::back_inserter(vi));   // need to #include <iterator>

全面的答案,:)。另外,新的列表初始化语法 std::vector<int> vi = {1,2,3,4}; 不会调用 vector<int> 的复制构造函数吗? - Alcott
好的,我将copy-list-initialization更改为direct-list-initialization。但实际上这可能不会有任何区别。 - fredoverflow
如果你真的想看透 OP 的真正意图,你应该推荐 reserveback_inserter 以及 std::iota :-) - Kerrek SB
@FredOverflow,direct-list-init是一种新的语法,对吗?我以前从未见过它,也没有初始化过任何向量。 - Alcott
@Alcott 这是C++11的语言特性。 - fredoverflow

1
除了其他答案之外,你不需要使用 reservecopy,因为在这里使用 assign 就足够了:

int main()
{
    int l[] = {1,2,3,4};
    vector<int> vi;
    vi.assign(l, l + 4); 

    do_stuff();
}

3
关于这一点,vector有一个构造函数,它接受两个迭代器作为参数。 - Steve Jessop

1

来自特定的 C++ 参考:

无论如何,对 [vector::reserve] 的调用都不会影响向量中包含的元素,也不会影响向量的大小(有关此事,请参见 vector::resizevector::erase,它们修改了向量的大小和内容)。


1
请不要称那个错误百出的网站为“C++文档”。人们可能会认为它是官方的东西。 - PlasmaHH

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