首页 > 解决方案 > 指针在 push_back 后被修改

问题描述

让我们考虑以下 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;
}

使用调试器,我注意到在第一次插入更改a 地址后a[0]。因此,当我在第二个 for 循环中打印时,我得到了对第一个条目的无效引用。为什么会这样?

谢谢你的帮助!

标签: c++

解决方案


  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
  }

直接的问题是Iterator invalidation。随着a增长,它会重新分配其存储以获得更多容量。这可能会使指针b指向已返回到 freestore(可能是堆)的内存。访问这些指针会调用未定义的行为,任何事情都可能发生。对此有一些解决方案,例如提前保留空间以消除重新分配或使用具有更宽容的失效规则的容器,但无论您做什么,下一个问题都会变得没有意义。

  while(!a.empty()){
    a.pop_back(); // remove item from `a`
  }

由于 in 中的项b指向 in 中的项,a并且 in 中没有项,因此现在 ina中的所有指针b都引用了无效对象,并且在不调用 Undefined Behaviour 的情况下无法访问。

只要项目 in存在或从和中删除,项目 ina引用的所有项目都必须保持活动状态。bbab

在这种微不足道的情况下,答案很简单,不要为空a,但这违背了示例的要点。对于一般情况有很多解决方案(只使用a, 存储副本而不是指针 in b,在两者中使用std::shared_ptr和存储shared_ptrs 到Asab)但是要提出有用的建议,我们需要知道如何a以及b正在被消费。


推荐阅读