c++ - 奇怪的迭代器行为 + unordered_set 的段错误

标签 c++ c++11 unordered-set

我有一个类有一个 unordered_set<int>成员如下:

我有以下类定义,后面是它的常规构造函数和复制构造函数,以及一些其他修改集合的函数(删除了不相关的代码段,因为类很长):

#include <iostream>
#include <unordered_set>
#include <random>

class HexBoard {
  public:
    HexBoard(int n);
    HexBoard(const HexBoard &obj);
    std::unordered_set<int> emptyPositions();
  private:
    std::unordered_set<int> empty_positions;
};

HexBoard::HexBoard(int n) {
    for (int i = 0; i < n * n; i++) {
        empty_positions.insert(i);
    }
}

HexBoard::HexBoard(const HexBoard &obj) : empty_positions(obj.empty_positions) {};

void HexBoard::placeStone(int i) {
    checkBounds(i); // raises an error if i >= n 
    empty_positions.erase(i);
}

std::unordered_set<int> HexBoard::emptyPositions() {
    return empty_positions;
}

我有一个包含此 HexBoard 实例的不同类。它有一个函数,可以使用复制构造函数将该板复制到不同的变量中:

class Game {
  public:
    Game(HexBoard::HexBoard *board) : board(board) {};
  private:
    HexBoard *board;
    void monteCarlo(int position);
};

void Game::monteCarlo(int position) {

    HexBoard *another_board = new HexBoard(*board);

    int count = 0;
    while (count < 5) {
        count++;

        std::uniform_int_distribution<unsigned> dis(
            0, another_board->emptyPositions().size() - 1
        );

        std::cout << "Empty positons:\n";
        for (const auto& pos : another_board->emptyPositions()) {
            std::cout << pos << " ";
        }
        std::cout << "\n";

        int n = dis(gen);
        std::cout << "Picked random n: " << n << "\n";

        auto it = another_board->emptyPositions().begin();
        std::cout << "it begin: " << *it << "\n";
        std::advance(it, n);
        std::cout << "it advance: " << *it << "\n";
        int absolute_position = *it;
        std::cout << "picked " << absolute_position << "\n";
    }
}

monteCarlo函数,比方说emptyPositions的内容最初设置为 8, 7, 6, 5, 4, 3, 2, 1 ,这个函数的标准输出通常是:

Empty positons:
8 7 6 5 4 3 2 1
Picked random n: 4
it begin: 2
Segmentation fault: 11

为什么会出现这个段错误?我知道关于 empty_positions.erase(i); 有一些巧妙的迭代器行,但即使我将其注释掉,我也会得到相同的行为。

我还在 Picked random n 之后添加了这个stdout 和这个段错误(输出在它下面):

std::cout << "set buckets contain:\n";
for ( unsigned i = 0; i < ai_board->emptyPositions().bucket_count(); ++i) {
    std::cout << "bucket #" << i << " contains:";
    for ( auto j = ai_board->emptyPositions().begin(i);
          j != ai_board->emptyPositions().end(i); ++j)
        std::cout << " " << *j;
    std::cout << std::endl;
}

输出:

set buckets contain:
Segmentation fault: 11

段错误发生在std::advance(it, n);以及最后一次手动迭代。

如果有任何帮助,我将不胜感激。

谢谢

最佳答案

我怀疑问题是 emptyPositions() 正在返回 unordered_set 的拷贝。因此,another_board->emptyPositions().begin() 从一个临时的迭代器中返回一个迭代器,其生命周期不能保证。在您遍历它之前,它可能正在清理。

您可能想让 emptyPositions() 返回对状态变量 empty_positions 的引用。

关于c++ - 奇怪的迭代器行为 + unordered_set 的段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42043692/

相关文章:

c++ - 哪个 C++ 库提供带有不强制执行比较函数的任何类型的键的映射?

c++ - 如何对 std::map 的值使用基于范围的 for 循环?

c++ - C++1z 范围的状态?

c++ - 是否可以防止 unordered_map::insert 抛出异常?

c++ - glDrawArrays 上的 OpenGL 段错误

c++ - 在我的 linux 中调用了哪个版本的 close(),来自 posix lib 还是内核?

c++ - std::make_pair: "cannot convert ‘int*’ 到 ‘std::pair<EndPointAddr*, EndPointAddr*>*’ 初始化”

c++ - 具有递归继承和使用声明的可变参数模板

c++ - 检查 unordered_set 是否包含其他 unordered_set 中的所有元素 - C++

c++ - 在C++中访问unordered_set的最后一个元素