由于向量元素是连续存储的,我猜它可能在一些push_back之后没有相同的地址,因为初始分配的空间是不够的。
我正在编写一个代码,我需要引用向量中的元素,例如:
int main(){
vector<int> v;
v.push_back(1);
int *ptr = &v[0];
for(int i=2; i<100; i++)
v.push_back(i);
cout << *ptr << endl; //?
return 0;
}
但ptr
包含对v[0]
的引用并不一定正确,对吧?怎样才能保证呢?
我的第一个想法是使用指针向量和动态分配。我想知道是否有更简单的方法吗?
PS:实际上我正在使用类的向量而不是int,但我认为问题是相同的。
答案 0 :(得分:12)
不要使用保留推迟这个悬空指针错误 - 作为有同样问题的人,耸耸肩,保留1000,然后几个月后花了很多年时间试图找出一些奇怪的内存错误(矢量容量超过1000),我可以告诉你这不是一个强大的解决方案。
如果可能的话,您希望避免使用向量中的元素地址,因为重新分配的不可预测性。如果必须,使用迭代器而不是原始地址,因为检查过的STL实现会告诉您它们何时变为无效,而不是随机崩溃。
最佳解决方案是更换容器:
答案 1 :(得分:10)
您可以通过调用其reserve
成员函数来增加向量使用的基础数组的容量:
v.reserve(100);
只要你没有在矢量中放置超过100个元素,ptr
将指向第一个元素。
答案 2 :(得分:6)
怎样才能保证呢?
std::vector<T>
保证是连续的,但是实现可以在更改向量内容的操作上自由重新分配或释放存储(向量迭代器,指针或对元素的引用也变得不确定)。
但是,您可以致电reserve
来获得所需的结果。 IIRC,该标准保证在向量大小大于其保留容量之前不进行重新分配。
一般来说,我会小心它(你很快就会陷入困境......)。除非你真的需要,否则最好不要依赖std::vector<>::reserve
和迭代器持久性。
答案 3 :(得分:5)
另一种可能的可能性是专用的智能指针,它不是存储地址而是存储矢量本身的地址以及你关心的项目的索引。然后它会把它们放在一起,只有当你取消引用它时才得到元素的地址,如下所示:
template <class T>
class vec_ptr {
std::vector<T> &v;
size_t index;
public:
vec_ptr(std::vector<T> &v, size_t index) : v(v), index(index) {}
T &operator*() { return v[index]; }
};
然后您的int *ptr=&v[0];
将替换为:vec_ptr<int> ptr(v,0);
有几点:首先,如果你在创建“指针”的时间和你取消引用它的时间之间重新排列向量中的项目,它将不再引用原始元素,而是引用任何元素碰巧在指定的位置。其次,这不进行范围检查,因此(例如)尝试在仅包含50个项目的向量中使用100 th 项将给出未定义的行为。
答案 4 :(得分:2)
正如James McNellis和Alexander Gessler所说,reserve
是预先分配记忆的好方法。但是,为了完整起见,我想补充一点,为了使指针保持有效,所有插入/删除操作必须从向量的尾部发生,否则项目移位将再次使指针无效。
答案 5 :(得分:2)
如果您不需要连续存储值,则可以使用std :: deque而不是std :: vector。它没有重新分配,而是将元素保存在几个内存块中。
答案 6 :(得分:1)
根据您的要求和使用案例,您可能需要查看Boost's Pointer Container Library。
在您的情况下,您可以使用boost::ptr_vector<yourClass>
。
答案 7 :(得分:1)
我也遇到了这个问题,花了一整天时间才发现矢量地址已经改变,保存的地址变得无效。对于我的问题,我的解决方案是那个
我找到了以下作品
但是,我还没弄清楚如何使用vector.front(),我不确定是否应该使用 pointers [i] = indices [i] * sizeof(vector)+(size_t)&amp; vector [0]。我认为参考方式(2)应该是非常安全的。