繁体   English   中英

奇怪的迭代器行为+带有unordered_set的segfault

[英]Weird iterator behaviour + segfault with 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);巧妙的迭代器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

segfault发生在std::advance(it, n); 并在最后的手动迭代。

我很感激任何帮助。

谢谢

我怀疑问题是emptyPositions()正在返回unordered_set的副本。 因此, another_board->emptyPositions().begin()从临时生成器返回迭代器,其生命周期无法保证。 在迭代之前,它可能正在被清理。

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

HexBoard类中,您有:

std::unordered_set<int> emptyPositions();

也就是说,函数返回一个按值设置。

然后你会做

auto it = another_board->emptyPositions().begin();

这将导致emptyPositions返回一个临时对象,一旦表达式完成就会被破坏。 这将为你留下一个迭代器,它是一个现在被破坏的集合中的一个键。 取消引用此迭代器将导致未定义的行为

解决方案是使emptyPositions返回一个常量引用:

std::unordered_set<int> const& emptyPositions() const;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM