说我有这个:
Object *myObject;
std::vector<Object> objects(99);
....
myObject = &objects[4];
可以安全地假设myObject的指针总是有效,无论对象[]有多大,如果我删除了一些,只要我不擦除()myObject指向的实际对象?或者它的工作方式不同?如果以上不起作用,我怎么能实现这一目标?这是因为在我的设计中,我希望一个孩子有一个指向其父项的指针,父项在添加子项时由父项指定,但是父项在std :: vector中,我需要随机访问。在我的情况下,std :: list会更好吗?
由于
答案 0 :(得分:5)
不,假设这绝对是不安全的。
该标准解释了什么将使标准容器上的迭代器失效?在向量迭代器失效的任何时候,指向它的指针也是如此。实际上,这意味着当向量调整大小时(包括在调用push_back()
时隐式),指向它的任何迭代器都将失效,指针就会失效。类似地,调用erase()
将使删除项后的指针无效,因为它们都必须向上移动以填充已擦除的空间。
std::list
会更好;你可以并行维护一个指向项目的指针向量,这些指针允许你通过索引访问它们,而不会让它们在内存中移动。
答案 1 :(得分:2)
如果向量填满其分配的空间并且您尝试插入更多空间,则需要重新分配其存储空间,这将涉及复制对象并销毁旧存储,这将使您保留的指针无效周围 - 所以不,这还不够好。
std :: list可以正常工作,因为它不依赖于连续存储,但是你失去了快速随机访问的能力。或者,您可以存储指向集合中对象的指针,在这种情况下,您可以取出该元素,指针将保持有效,直到您在代码中释放该内存 - 但您需要在某些时候自己处理
另一种选择可能是deque;虽然deque迭代器由push_back
无效,但对元素的直接引用(如此处使用的指针)仍然有效。
答案 2 :(得分:1)
如果你保持向量的大小相同,你可以通过在声明它之后用reserve()
和最大数量的元素来调用它来保证这一点,或者(如你所做的那样)用每个构造到的元素的初始数量来声明它拥有默认元素值。
如果删除或添加元素,则可以随时重新分配基础存储。
由于您在此处使用原始指针,因此可以使用NULL作为“空元素”标志来保持存储不变。由于您最初使用99进行设置,因此它们之后将全部为NULL(任何指针作为向量元素的默认值),reserve
是多余的,除非您计划扩展列表。
允许您不用担心矢量存储的选项是将元素存储为boost::shared_ptr<Object>
。然后,如果没有其他人正在使用它,那么vector
元素的任何删除实际上只会delete
引用的Object
实例。
boost::shared_ptr<Object> myObject;
std::vector<boost::shared_ptr<Object> > objects(99);
myObject = &objects[4];
objects.clear();
// myObject still valid since Object instance referenced thru shared_ptr
答案 3 :(得分:0)
奇怪,但没有人提到boost::stable_vector的事情:
...只要元素未被擦除,对stable_vector元素的引用和迭代器保持有效,并且已经分配了end()返回值的迭代器始终保持有效,直到相关的stable_vector被销毁为止