让我们考虑以下 C++ 代码
#include <iostream>
#include <vector>
class A {
int x, y;
public:
A(int x, int y) : x(x), y(y){}
friend std::ostream & operator << (std::ostream & os, const A & a){
os << a.x << " " << a.y;
return os;
}
};
int main(){
std::vector<A> a;
std::vector<const A*> b;
for(int i = 0; i < 5; i++){
a.push_back(A(i, i + 1));
b.push_back(&a[i]);
}
while(!a.empty()){
a.pop_back();
}
for(auto x : b)
std::cout << *x << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
使用调试器时,我注意到在第一次插入更改a
地址后a[0]。因此,当我在第二个 for 循环中打印时,我得到了对第一个条目的无效引用。为什么会发生这种情况?
谢谢你的帮助!
for(int i = 0; i < 5; i++){
a.push_back(A(i, i + 1)); //add a new item to a
b.push_back(&a[i]); // point at the new item in a
}
Run Code Online (Sandbox Code Playgroud)
直接的问题是Iterator invalidation。随着a增长,它会重新分配其存储空间以获得更多容量。这可能会使指针b指向已返回到 freestore(可能是堆)的内存。访问这些指针会调用未定义行为,任何事情都可能发生。有一些解决方案,例如提前保留空间以消除重新分配或使用具有更宽容失效规则的容器,但是无论您做什么,下一个问题都会变得毫无意义。
while(!a.empty()){
a.pop_back(); // remove item from `a`
}
Run Code Online (Sandbox Code Playgroud)
由于项目 inb指向项目 ina并且在 中没有项目a,b现在所有的指针都引用了无效的对象,并且无法在不调用未定义行为的情况下访问。
只要项目 in存在或从和 中删除,则 items ina引用的所有项目都b必须保持活动状态。bab
在这个微不足道的情况下,答案很简单,不要为空a,但这违背了示例的要点。对于一般情况有很多解决方案(只是使用a、存储副本而不是指针 in b、使用std::shared_ptr并将shared_ptrs存储到Asa和b)但要提出有用的建议,我们需要知道如何使用a和b正在使用。