我正在尝试为纸牌游戏Avalon实现贝叶斯估计器。游戏共有五轮,每轮最多包含五个不同玩家提出的五个建议。如果提议被接受,则玩家继续执行任务,然后游戏进入下一轮。在上一轮比赛结束之前,尚不知道哪5名球员将在下一轮比赛中提议球队。我想跟踪当前使用迭代器向团队提出建议的玩家,但最终它指向无处。具体来说,在要求的构造函数中round1
,迭代器Round::proposer
正确指向&PlayerA
的开始Round::proposers
。然而,当我这个实例(或它的?副本)添加到Game::rounds
,那么团成员proposer
的Game::rounds.back()
点无门,即使团成员proposers
仍然是正确的。为什么会这样呢?在执行期间,当然会在call期间引发读取访问冲突异常(*Round::proposer)->make_proposal();
。对于冗长的问题,我深表歉意,但似乎需要两个间接级别才能产生此错误。
// Player.h
#include <string>
class Player
{
private:
std::string name;
public:
Player(std::string name) : name(name) {};
void make_proposal() const {};
};
// Round.h
#include "Player.h"
#include <vector>
class Round
{
private:
std::vector<const Player*> proposers;
std::vector<const Player*>::const_iterator proposer;
public:
Round(std::vector<const Player*> proposers) : proposers(proposers), proposer(Round::proposers.begin()) {};
void next_proposal() { (*Round::proposer)->make_proposal(); };
};
// Game.h
#include "Round.h"
#include <vector>
class Game
{
private:
std::vector<Player*> players;
std::vector<Player*>::iterator active_player;
std::vector<Round> rounds;
public:
Game(std::vector<Player*> players);
void advance_player();
void next_round();
};
// Game.cpp
#include "Game.h"
Game::Game(std::vector<Player*> players)
: players(players), active_player(Game::players.begin())
{
std::vector<Player*>::const_iterator player = Game::players.begin();
std::vector<const Player*> proposers = { *player };
for (unsigned int i = 0; i < 4; ++i) {
++player;
if (player == Game::players.end()) player = Game::players.begin();
proposers.push_back(*player);
}
Round round1(proposers);
Game::rounds = { round1 };
}
void Game::next_round()
{
Game::rounds.back().next_proposal();
}
#include <iostream>
#include "Game.h"
int main()
{
Player playerA("A");
Player playerB("B");
Player playerC("C");
Player playerD("D");
Player playerE("E");
Player playerF("F");
std::vector<Player*> players = { &playerA, &playerB, &playerC, &playerD, &playerE, &playerF };
Game game(players);
for(unsigned int i = 0; i < 5; ++i) {
game.next_round();
}
}
令人惊讶的是,替换了两行代码
Round round1(proposers);
Game::rounds = { round1 };
在Game.cpp
与
Round* round1 = new Round(proposers);
Game::rounds = { *round1 };
解决了这个问题,尽管我真的不明白为什么。毕竟,rounds
是的成员变量,Game
并且存在直到实例game
被销毁为止。此hack的后续问题:round1
上一个代码片段中指向的实例Game
是否被类的默认构造函数破坏了,因为在添加到成员变量之前已取消引用该实例?
你Round
不能毫无问题地复制:
class Round
{
private:
std::vector<const Player*> proposers;
std::vector<const Player*>::const_iterator proposer;
public:
Round(std::vector<const Player*> proposers) : proposers(proposers), proposer(Round::proposers.begin()) {};
void next_proposal() { (*Round::proposer)->make_proposal(); };
};
如果确实要复制它,proposer
它将仍然是原始元素的迭代器,而Round
不是副本中的向量。执行此操作时:
Round* round1 = new Round(proposers);
Game::rounds = { *round1 };
然后,本地对象不会在作用域的结尾处round1
被销毁,因此,在复制之后,位于内部的迭代器将引用仍在运行的元素。尽管它指的是内部的元素,但并不是您放置的元素。rounds
round1
round1
Round
rounds
要么注意3/5
for的规则Round
,要么使用索引而不是迭代器。复制整个向量时,索引不会无效。(当您将更多元素推回向量时,它们也不会失效,但是迭代器会这样做)
一个类似问题的简单示例:
#include <iostream>
struct broken {
int x;
int* ptr;
broken(int a = 0) : x(a),ptr(&x) {}
};
int main() {
broken a{42};
broken b{123};
a = b;
a.x = 0;
std::cout << *(a.ptr);
}
复制b
到a
指针后,ina
仍将指向b.x
,因此输出为123
(不是0
人们期望的那样)。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句