我的std::vector
包含某些类ClassA
的元素。另外,我想使用std::map<key,ClassA*>
创建一个索引,它将一些键值映射到指向向量中包含的元素的指针。
当向量的末尾添加(不是插入)时,是否保证这些指针保持有效(并指向同一个对象)。即,以下代码是否正确:
std::vector<ClassA> storage;
std::map<int, ClassA*> map;
for (int i=0; i<10000; ++i) {
storage.push_back(ClassA());
map.insert(std::make_pair(storage.back().getKey(), &(storage.back()));
}
// map contains only valid pointers to the 'correct' elements of storage
如果我使用std::list
代替std::vector
?
答案 0 :(得分:25)
向量 - 否。因为向量的容量永远不会缩小,所以即使删除或更改了元素,也可以保证引用,指针和迭代器保持有效,只要它们引用操作元素之前的位置即可。但是,插入可能会使引用,指针和迭代器无效。
列表 - 是的,插入和删除元素不会使指针,引用和其他元素的迭代器无效
答案 1 :(得分:9)
据我所知,没有这样的保证。向向量中添加元素将导致元素重新分配,从而使地图中的所有指针无效。
答案 2 :(得分:6)
使用std::deque
!仅使用push_back()
时,元素的指针是稳定的。
注意:元素的迭代器可能无效!指向元素的指针不会。
编辑:此答案解释了原因:C++ deque's iterator invalidated after push_front()
答案 3 :(得分:3)
我不确定它是否有保证,但实际上storage.reserve(needed_size)
应该确保不会发生重新分配。
但为什么不存储索引呢?
通过将索引添加到开始迭代器(storage.begin()+idx
)可以很容易地将索引转换为迭代器,并且通过首先取消引用它,然后获取其地址(&*(storage.begin()+idx)
),可以很容易地将任何迭代器转换为指针。
答案 4 :(得分:1)
只要让它们成为存储指针,就可以在不需要时明确删除对象。
std::vector<ClassA*> storage;
std::map<int, ClassA*> map;
for (int i=0; i<10000; ++i) {
ClassA* a = new ClassA()
storage.push_back(a)
map.insert(std::make_pair(a->getKey(), a))
}
// map contains only valid pointers to the 'correct' elements of storage
答案 5 :(得分:1)
从其中一个评论到另一个答案,似乎所有你想要的是集中(轻松)内存管理。如果确实如此,您应该考虑使用预先打包的解决方案,例如boost pointer container库,并尽可能简化您自己的代码。
请特别注意ptr_map
答案 6 :(得分:0)
列表是。 怎么样? 迭代器用作指向列表中特定节点的指针。 所以你可以为任何结构分配值,如:
列出mylist;
一对&LT; list :: iterator,int&gt;温度;
temp = make_pair(mylist.begin(),x);