首页 > 解决方案 > 使用基于范围的 for 循环和指针向量时的 C++ 错误

问题描述

在处理指针向量时,我偶然发现了这个奇怪的错误:

mwe.cpp

#include <iostream>
#include <vector>

class A {
  public:
    int x = 42; // making this unsigned causes output to be only positive
    int y;      // removing this makes bug disappear
};

class B {
  public:
    B(std::vector<A *> pt_vec) {
      std::cout << pt_vec[0]->x << std::endl;
    };
};

int main() {
  std::vector<A *> pt_vec;

  A a;                 //  these 3 lines can
  std::vector<A> vec;  //  be replaced with
  vec.push_back(a);    //  std::vector<A> vec {A()};
                       //  the bug will still appear

  for (A el: vec) {         // doing this without for (or
    pt_vec.push_back(&el);  // with iterators/good ol' for)
  }                         // makes bug disappear

  B b = B(pt_vec);

  //exit(1);    // uncommenting this makes bug disappear
}

如何重现:

$ gcc --version
gcc (Gentoo 9.2.0-r2 p3) 9.2.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ g++ -O0 -Wall -Wpedantic mwe.cpp -o mwe
mwe.cpp: In function ‘int main()’:
mwe.cpp:27:5: warning: variable ‘b’ set but not used [-Wunused-but-set-variable]
   27 |   B b = B(pt_vec);
      |     ^

(错误也在 ARCH 上使用 GCC 9.2.0 重现,但 Apple clang 11.0.0 给出了预期的输出)

预期输出:

$ ./mwe
42

实际输出:

$ ./mwe 
1533476528
$ ./mwe
-1607700816
$ ./mwe
<insert random huge number here>

我是否无意中在某处引入了未定义行为?如果没有,为什么这不能按预期工作?

标签: c++pointersgccvector

解决方案


for (A el: vec)意味着您在vec迭代时正在创建每个元素的副本。&el将是一个指向将在迭代结束时死亡的对象的指针。

你想用引用for (A& el: vec)来遍历元素vec&el然后将是指向内部实际元素的指针vec


推荐阅读