为什么“this”等于0x0,导致我的程序崩溃

Why is `this` equal to 0x0, causing my program to crash?

本文关键字:我的 程序 崩溃 0x0 this 等于 为什么      更新时间:2023-10-16

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

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

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

Board - 代表游戏板。它包含尺寸,以及具有这些尺寸的Tile s的2D矢量。

Tile - Board 中的嵌套类。表示板上的一个空格。每个Tile都有一个Colour,并且与该磁贴的所有者std::unique_ptr。所有者从nullptr开始,可以更改为Player一次。颜色从透明的黑色开始。


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

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

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

循环遍历带有i的行和带有j的列,这是您希望打印它的方式。

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>.它首先检查磁贴的所有者之前是否被设置过(即未nullptr)。如果没有,它将里面的Player设置为传入的那个。然后,它会更新磁贴的颜色并返回true 。如果之前已声明磁贴,则返回false

在调试器之后,崩溃发生在行*_owner = owner; 中。介入将我带到第 struct Player 行(我对 Player 类的声明),我将其视为隐式复制构造函数(请记住,该类只有一个Colour _colour和一个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()这只是return _red;。这是程序崩溃的点。调试器声明thisthis->_red)是0x0。

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

this被0x0的原因可能是什么?

编辑:
我确定一切都被初始化了,因为我在每个构造函数中都这样做了,在成员初始值设定项中(例如 Board::Tile::Tile() : _colour (Colours::NONE), _owner (nullptr){} ),其中 NONE 是透明的黑色。

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

*_owner = owner;

意思是"复制owner对象,并将其存储在_owner指向的位置。 问题是_owner还没有指向任何东西;它仍然为空。

如果您确实想在玩家控制的每个磁贴中复制Player对象,则需要这样做

_owner.reset(new Player(owner));

但是复制Player对象是一件奇怪的事情。 考虑改用shared_ptr - 您可以让owner_ownershared_ptr,并以通常的方式将一个分配给另一个。

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

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

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

相关文章: