当我使用vector存储一些数据时,我通常通过向量的第一个条目的指针访问这些数据。因为它比at()方法更快。但我意识到,当我插入一个数据块时,说一个数组到向量的末尾,第一个条目的指针会改变。这可能是堆栈的东西,但如果我通过push_back一次添加一个元素,第一个指针不会改变。那为什么呢?我应该担心使用指针来访问元素吗?
以下是想要结帐的人的示例代码:
int arrayLen = 500000;
vector<int> vint = vector<int>(2000,0);
int * firstEntry = &vint[0];
int * iarray = new int[arrayLen];
for(int i = 0; i< arrayLen; i++)
{
iarray[i] = i;
}
vint.insert(vint.end(),iarray,iarray+arrayLen);
cout << firstEntry << "," << &vint[0] << endl; // They ar not equal;
// reset the vector
vint.clear();
vint.resize(2000,0);
firstEntry = &vint[0];
for(int i = 0; i< arrayLen; i++)
{
vint.push_back(iarray[i]);
if(firstEntry != &vint[0])
cout << firstEntry << "," << &vint[0] <<","<< i << endl;
}// nothing is written
cout << firstEntry << "," << &vint[0] << endl; // now they are equal;
答案 0 :(得分:4)
std :: vector可以动态调整大小。它的方式是保持比所需更多的空间。一旦达到保留容量,就需要保留更大的数据块(取决于实现,但新块的容量通常是之前大小的两倍)。然后将数据复制到新位置,这就是第一个元素的地址发生变化的原因。
如果不向向量添加更多数据,则无需担心向量中的数据指针无效。您可以通过检查vint.capacity()== vint.size()来预测何时进一步的push_back()将触发调整大小。您也可以通过始终使用最新的via&amp; vint [0](或&amp; vint.at()来获取范围检查)而不是复制它来避免使用无效指针。
如果您知道要插入一些新项目,则可以通过使用reserve()预分配空间(如果当前容量小于请求的容量)来确保您有足够的容量。但请注意,你不想零碎地做这件事 - 例如
vint.reserve(vint.size() + 2000);
for(int i=0; i<2000; ++i) {
vint.push_back(i);
}
没关系,但是
for(int i=0; i<2000; ++i) {
vint.reserve(vint.size() + 1);
vint.push_back(i);
}
由于你反复要求操作系统获得更多内存并且每次迭代都会产生越来越大的复制操作,因此将会降低性能。
答案 1 :(得分:2)
向量可能会重新分配到堆上更大的内存区域。如果你想要更高的性能,你应该使用[]
而不是at()
,但是你必须确保你的指数在范围内:通常很容易确保。这是非常糟糕的做法,并且完全不需要从向量指针开始更喜欢缓存和索引:只需启用优化器并确保您没有使用STL的某些调试模式“已检查迭代器”模式(如果有一个,例如Visual C ++),无论如何,性能都是相同的。
如果你知道矢量可能增长的最大尺寸,那么你可以使用reserve()预先调整它的大小。
答案 2 :(得分:1)
在插入许多元素之前,使用reserve()
来防止多个内存分配。
然后得到你的“第一个指针”,如果你正确保留了正确数量的元素,这个指针不应该改变。
但为什么不使用begin()
? *
和->
运算符可以解决这个问题,你知道......