[英]Const_iterator member variable not pointing to the begin of a vector member variable after initialization
I am trying to implement a Bayesian estimator for the card game Avalon.我正在尝试为纸牌游戏 Avalon 实现贝叶斯估计器。 The game has five rounds and each round contains at most five proposals made by five different players.
游戏有五轮,每轮最多包含五个不同玩家提出的五个建议。 If a proposal is accepted, players go on a quest and the game proceeds to the next round.
如果提议被接受,玩家 go 将进行任务,游戏进入下一轮。 Before the previous round is completed, it is not known which 5 players will get to propose teams in the next round.
在上一轮完成之前,尚不清楚下一轮将有哪5名球员提出球队。 I wanted to keep track of the current player that gets to propose a team using an iterator, but somehow it ends up pointing to nowhere.
我想跟踪使用迭代器提议团队的当前玩家,但不知何故它最终指向无处。 Specifically, in the constructor called for
round1
, the iterator Round::proposer
points correctly to &PlayerA
, the beginning of Round::proposers
.具体来说,在调用
round1
的构造函数中,迭代器Round::proposer
proposer 正确指向&PlayerA
,即Round::proposers
proposers 的开头。 However, when I add this instance (or a copy of it?) to Game::rounds
, then the Round member proposer
of Game::rounds.back()
points nowhere, even though the Round member proposers
is still correct.但是,当我将此实例(或它的副本?)添加到
Game::rounds
时, Game::rounds.back()
的 Round 成员proposer
无处可去,即使 Round 成员proposers
仍然正确。 Why does that happen?为什么会这样? During execution, of course a read access violation exception is thrown during the call
(*Round::proposer)->make_proposal();
在执行过程中,当然会在调用过程中抛出读访问冲突异常
(*Round::proposer)->make_proposal();
. . I apologize for the lengthy question, but two levels of indirection seemed necessary to produce the error.
我为这个冗长的问题道歉,但似乎需要两个级别的间接来产生错误。
// 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();
}
}
Surprisingly, replacing the two lines of code令人惊讶的是,替换了两行代码
Round round1(proposers);
Game::rounds = { round1 };
in Game.cpp
with在
Game.cpp
中
Round* round1 = new Round(proposers);
Game::rounds = { *round1 };
fixes the issue, although I really don't understand why.解决了这个问题,虽然我真的不明白为什么。 After all,
rounds
is a member variable of Game
and exists until instance game
is destroyed.毕竟,
rounds
是Game
的成员变量,并且存在直到实例game
被销毁。 Follow-up question to this hack: is the instance to which round1
points in the last code snippet destroyed by the default constructor of class Game
since it is dereferenced before adding to the member variable?这个hack的后续问题:最后一个代码片段中
round1
指向的实例是否被class Game
的默认构造函数破坏,因为它在添加到成员变量之前被取消引用?
Your Round
cannot be copied without problems:您的
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(); };
};
If you do copy it, the proposer
will still be an iterator to an element in the original Round
not to the vector in the copy.如果你复制它,
proposer
仍然是原始Round
中元素的迭代器,而不是副本中的向量。 When you do this:当你这样做时:
Round* round1 = new Round(proposers);
Game::rounds = { *round1 };
Then the local object round1
is not destroyed at the end of the scope, hence the iterator that is now inside rounds
, after making a copy of round1
, refers to an element that is still alive.然后本地 object
round1
在 scope 结束时不会被破坏,因此现在在rounds
内部的迭代器,在制作了round1
的副本之后,指的是仍然活着的元素。 Though it refers to the element inside round1
, not to the Round
that you placed in rounds
.尽管它指的是
round1
内的元素,而不是您放置在rounds
中的Round
。
Either take care of the rule of 3/5
for Round
, or use indices instead of iterators.要么注意
Round
的3/5
规则,要么使用索引而不是迭代器。 Indices get not invalidated when the whole vector is copied.复制整个向量时,索引不会失效。 (They also get not invalidated when you push back more elements to the vector, but iterators do)
(当您将更多元素推回向量时,它们也不会失效,但迭代器会)
A simpler example for similar problem:类似问题的更简单示例:
#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);
}
After copying b
to a
the pointer in a
will still point to bx
, hence output is 123
(not 0
as one might expect).将
b
复制到a
后, a 中a
指针仍将指向bx
,因此 output 为123
(而不是预期的0
)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.