【问题标题】:Using map<int, Foo> instead of vector<Foo> to avoid pointer invalidation使用 map<int, Foo> 而不是 vector<Foo> 来避免指针失效
【发布时间】:2019-07-28 23:03:41
【问题描述】:
假设我有一个类 Foo 和一个容器 vector<Foo> Foos。
我使用的算法严重依赖于指向Foos 元素的指针,并且我还需要动态添加Foos 并访问容器的元素。问题是如果我向向量中添加太多元素,它可能需要重新分配元素,从而使指向这些元素的所有指针无效。那么使用map<int, Foo> 代替vector<Foo> 是否有意义?
【问题讨论】:
标签:
c++
dictionary
vector
stl
containers
【解决方案1】:
std::deque 与向量具有相似的性能(和随机访问),但不会在插入时使指针无效。
但它确实使删除指针无效。
【解决方案2】:
我会使用std::vector<std::shared_ptr<Foo>>,所以我仍然有一个向量,并且无论它们在向量中的位置如何,我仍然有有效的指针。
【解决方案3】:
这个答案的重点是如何防止指针失效发生,同时仍然坚持std::vector。
预分配
如果您事先知道向量可以包含的Foo 对象的最大数量,您可以简单地使用std::vector::reserve() 成员函数重新分配向量的缓冲区。这样,对象的重新分配就不会发生,因此指向Foo 对象的指针也不会失效。
使用指针向量
或者,您可以使用std::vector<std::unique_ptr<Foo>> 代替std::vector<Foo>。这样,即使向量重新分配其元素,指向的Foo 对象的地址也不会改变,因为将重新分配的是std:unique_ptr<Foo> 对象,而不是Foo 对象。因此,指向Foo 对象的指针仍然有效。
后一种方法引入了额外的间接层,因此效率低于前一种。
【解决方案4】:
你有四种可能:
您使用了非无效容器。这是你的建议。
您事先在向量中保留了足够的空间 (El Professor's answer)。这仅在您提前知道Foos 的最大数量时才有效。
您使用(智能)指针向量 (Michael Chourdakis' answer)。只要您不需要将指针用作迭代器,这就会起作用。
您没有对 vector<Foo> 进行任何更改,但是您可以使用索引而不是指针来使您的算法工作。这允许您查看之前和之后的元素(在检查向量边界之后),并且索引不会因重新分配而失效。