簡體   English   中英

Const_iterator 成員變量在初始化后未指向向量成員變量的開頭

[英]Const_iterator member variable not pointing to the begin of a vector member variable after initialization

我正在嘗試為紙牌游戲 Avalon 實現貝葉斯估計器。 游戲有五輪,每輪最多包含五個不同玩家提出的五個建議。 如果提議被接受,玩家 go 將進行任務,游戲進入下一輪。 在上一輪完成之前,尚不清楚下一輪將有哪5名球員提出球隊。 我想跟蹤使用迭代器提議團隊的當前玩家,但不知何故它最終指向無處。 具體來說,在調用round1的構造函數中,迭代器Round::proposer proposer 正確指向&PlayerA ,即Round::proposers proposers 的開頭。 但是,當我將此實例(或它的副本?)添加到Game::rounds時, Game::rounds.back()的 Round 成員proposer無處可去,即使 Round 成員proposers仍然正確。 為什么會這樣? 在執行過程中,當然會在調用過程中拋出讀訪問沖突異常(*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 };

解決了這個問題,雖然我真的不明白為什么。 畢竟, roundsGame的成員變量,並且存在直到實例game被銷毀。 這個hack的后續問題:最后一個代碼片段中round1指向的實例是否被class 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 };

然后本地 object round1在 scope 結束時不會被破壞,因此現在在rounds內部的迭代器,在制作了round1的副本之后,指的是仍然活着的元素。 盡管它指的是round1內的元素,而不是您放置在rounds中的Round

要么注意Round3/5規則,要么使用索引而不是迭代器。 復制整個向量時,索引不會失效。 (當您將更多元素推回向量時,它們也不會失效,但迭代器會)


類似問題的更簡單示例:

#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后, a 中a指針仍將指向bx ,因此 output 為123 (而不是預期的0 )。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM