this post的评论部分中有一个关于使用std::vector::reserve()
与std::vector::resize()
的帖子。
以下是原始代码:
void MyClass::my_method()
{
my_member.reserve(n_dim);
for(int k = 0 ; k < n_dim ; k++ )
my_member[k] = k ;
}
我认为要在vector
中编写元素,正确的做法是调用 std::vector::resize()
,而不是std::vector::reserve()
。
实际上,以下测试代码在VS2010 SP1的调试版本中“崩溃”:
#include <vector>
using namespace std;
int main()
{
vector<int> v;
v.reserve(10);
v[5] = 2;
return 0;
}
我是对的,还是我错了?并且VS2010 SP1是对的,还是错了?
答案 0 :(得分:94)
出于某种原因,有两种不同的方法:
std::vector::reserve
将分配内存,但不会调整您的矢量大小,其逻辑大小与以前相同。
std::vector::resize
实际上会修改矢量的大小,并将填充处于默认状态的对象的任何空间。如果它们是整数,它们都将为零。
保留后,在你的情况下,你需要很多push_backs来写入元素5。 如果您不希望这样做,那么在您的情况下,您应该使用调整大小。
答案 1 :(得分:21)
由 Jan Hudec :Choice between vector::resize() and vector::reserve()
回答这两个功能完全不同。
resize()方法(以及传递给构造函数的参数等价于此)将向向量插入给定数量的元素(它具有可选的第二个参数来指定它们的值)。它将影响size(),迭代将遍历所有这些元素,push_back将在它们之后插入,您可以使用operator []直接访问它们。
reserve()方法只分配内存,但保留未初始化状态。它只影响capacity(),但size()将不变。对象没有值,因为向量中没有添加任何内容。如果然后插入元素,则不会重新分配,因为它是事先完成的,但这是唯一的效果。
所以这取决于你想要什么。如果需要1000个默认项的数组,请使用resize()。如果您想要一个数组,您希望插入1000个项目,并希望避免一些分配,请使用reserve()。
编辑:Blastfurnace的评论使我再次阅读了这个问题并意识到,在您的情况下,正确的答案是不要手动预分配。只需根据需要在元素末端插入元素即可。向量将根据需要自动重新分配,并且比上述手动方式更有效。 reserve()有意义的唯一情况是,您需要提前轻松获得所需总大小的合理精确估计。EDIT2:广告问题编辑:如果您有初步估算值,那么估计值为reserve(),如果结果不够,只需让矢量做就好了。
答案 2 :(得分:11)
这取决于你想做什么。 reserve
不添加任何内容
vector
的元素;它只会更改capacity()
保证添加元素不会重新分配(例如
使迭代器无效)。 resize
会立即添加元素。如果你想
要稍后添加元素(insert()
,push_back()
),请使用reserve
。如果你
想要稍后访问元素(使用[]
或at()
),请使用resize
。所以
你MyClass::my_method
可以是:
void MyClass::my_method()
{
my_member.clear();
my_member.reserve( n_dim );
for ( int k = 0; k < n_dim; ++ k ) {
my_member.push_back( k );
}
}
或
void MyClass::my_method()
{
my_member.resize( n_dim );
for ( int k = 0; k < n_dim; ++ k ) {
my_member[k] = k;
}
}
您选择的是品味问题,但您引用的代码是 显然不正确。
答案 3 :(得分:2)
是的,你是对的,Luchian只是写了一个错字,而且可能太缺乏咖啡而无法实现他的错误。
答案 4 :(得分:2)
可能应该讨论何时调用两个方法的数字比矢量的当前大小少。
使用小于容量的数字拨打reserve()
不会影响尺寸或容量。
使用小于当前大小的数字调用resize()
,容器将减少到该大小,从而有效地摧毁多余的元素。
总结resize()
将释放内存,而reserve()
则不会。
答案 5 :(得分:1)
调整大小实际上会更改向量中的元素数量,如果调整大小导致向量增长,则新项目将默认构造。
vector<int> v;
v.resize(10);
auto size = v.size();
在这种情况下,大小为10。
另一方面,保留只请求内部缓冲区增长到指定大小但不改变数组的“大小”,只改变其缓冲区大小。
vector<int> v;
v.reserve(10);
auto size = v.size();
在这种情况下,大小仍为0。
所以要回答你的问题,是的,你是对的,即使你保留足够的空间,你仍然使用索引运算符访问未初始化的内存。使用一个不那么糟糕的int但是在类向量的情况下,您将访问尚未构造的对象。
对于设置为调试模式的编译器的边界检查显然会被这种行为混淆,这可能是您遇到崩溃的原因。