4

我正在设计一个简单的 Connect 4 游戏。到目前为止,我有 4 个基础类:

Colour- 负责表示颜色(RGBA)。包括转换运算符。

Player- 代表游戏的玩家。每个Player都有一个Colour和一个名字。

Board- 代表棋盘。它包含维度,以及Tile具有这些维度的 s 的二维向量。

Tile- 内的嵌套类Board。代表板上的一个空间。每个瓷砖的所有者Tile都有一个Colour和一个。std::unique_ptr所有者以 开头,nullptr并且可以更改一次Player。颜色以透明黑色开始。


我已经测试了我的Colour课程,它似乎工作正常。我的Player班级也处于最佳状态。但是,我在Board/Tile上课时遇到了一些问题。

我的测试包括创建两个玩家和一个棋盘。这些正常执行。接下来,我遍历电路板的尺寸,每个瓷砖一次。然后我打电话

board.tile (j, i).claimBy (p2); 

循环遍历带有 的行和带有的ij,这是您期望的打印方式。

tile (j, i)检索我正在使用的图块。它按预期工作。


导致崩溃的事件链:

claimBy (p2)设置牌被玩家 2 认领。它的实现如下:

bool Board::Tile::claimBy (const Player &owner)
{
    if (!_owner)
    {
        *_owner = owner;
        _colour = owner.colour();
        return true;
    }

    return false;
}

_owner是我的std::unique_ptr<Player>。它首先检查之前是否设置了图块的所有者(即 is not nullptr)。如果不是,它将Player内部设置为传入的那个。然后它更新瓦片的颜色并返回true。如果该图块先前已被认领,则返回false

在调试器之后,崩溃发生在*_owner = owner;. 介入将我带到行struct Player(我的Player类声明),我认为它是隐式复制构造函数(请记住该类只有 aColour _colour和 a std::string _name)。

再次介入会导致我Colour::operator=(这对于调用复制构造函数是有意义的)。这是定义:

Colour &Colour::operator= (const Colour &rhs)
{
    if (*this != rhs)
    {
        _red = rhs.red();
        _green = rhs.green();
        _blue = rhs.blue();
        _alpha = rhs.alpha();
    }

    return *this;
}

路径变为*this != rhs。这只是对 的反向调用operator==,即:

return red() == rhs.red()
    && green() == rhs.green()
    && blue() == rhs.blue()
    && alpha() == rhs.alpha();

red() == rhs.red()这里的第一个比较red()是 just return _red;。这是程序崩溃的地方。调试器声明this( this->_red) 为 0x0。

我不知道为什么会这样。我最好的猜测是我错误地使用了智能指针。我以前从未真正使用过它,但它应该与普通指针非常相似,而且我认为release如果指针是nullptr.

this0x0的原因可能是什么?

编辑:
我确定一切都已初始化,正如我在每个构造函数中所做的那样,在成员初始化程序(例如Board::Tile::Tile() : _colour (Colours::NONE), _owner (nullptr){})中,其中 NONE 是透明的黑色。

我也不太精通调试器,因为在打印调试值时我并没有太多使用它。

4

2 回答 2

3

线

*_owner = owner;

意思是“制作对象的副本owner,并将其存储在_owner指向的位置”。问题是_owner它还没有指向任何东西。它仍然是空的。

如果您真的想在玩家控制的每个图块中制作对象的副本Player您需要这样做

_owner.reset(new Player(owner));

但是复制Player对象是一件奇怪的事情。考虑shared_ptr改用——你可以同时拥有owner_ownerbe shared_ptrs,并以通常的方式将一个分配给另一个。

于 2012-04-26T01:59:52.017 回答
1

你从一个默认的初始化开始std::unique_ptr<Player>。也就是说,相当于一个带有一些清理语义的NULL指针。然后您尝试在语句中取消引用它,*_owner=owner;以便您可以分配给它。

因此该语句*_owner=owner;基本上等同于((Player*)NULL)->operator=(owner);调用隐式赋值运算符。这样做的第一件事就相当于((Player*)NULL)->_colour=owner._colour; Findingthis==NULL在这里并不奇怪;确实,这是意料之中的。

修复取决于您实际想要发生的事情。是否应该给每个Board::Tile人一个全新的副本owner?然后你想改为说_owner.reset(new Player(owner)). 您是否只想让每个图块都包含对现有玩家的引用?你能保证 Player 对象的owner寿命会比 Board::Tile 对象长吗?然后你想要一个原始指针:(在 Board::Tile 的声明中)Player const *_owner;(在实现中)_owner=&owner;

于 2012-04-26T02:12:06.600 回答