0

编辑:

我已经实现了复制构造函数(都来自建议的答案)。我已经在我的控制器类以及它的子类中的等效版本中做到了这一点。但是,这并没有解决问题。此外,函数中的计数器和控制台注释removePawn()(程序中唯一调用 delete 的地方)表明它只被调用一次。

更详细地说,每个子类都有一个实例(不是指针)。这些是在我的world课堂上声明的。两者都通过类指针用作相同world类方法中的参数。baseController问题是,虽然两者都以相同的顺序执行相同的进程,但如果一个类removePawn()调用了它,则程序很好并且将继续运行。但是,如果第二个类removePawn()(特别是删除)调用了它,它会在该指令处使程序崩溃。

我也查了地址。分配后指针的地址与删除点的地址相同。

更多信息:仅当玩家被杀死(删除然后给予新棋子)时,我才会在关闭程序时收到分段错误。但是,如果程序在第一次新删除和最后一次删除的情况下启动然后关闭,那么它运行得非常好。

原来的:

我在使用指针时遇到了一些麻烦。我理解他们并相信我的代码相当健壮,但是在调用这部分代码时我似乎完全崩溃了。

Pawn 是一个初始化为 NULL 的 basePawn*。

if (pawn != NULL)
{
    cout << "Calling delete.\n";
    delete pawn;
    pawn = NULL;
}

这是 PS2 程序的大学作业,所以我的调试仅限于控制台的基本打印。

删除删除行允许主要的新建/删除部分运行几次,但它最终也会崩溃(我认为这是因为达到了内存限制,但我不能确定)

我检查了所有常见的罪魁祸首,指针被初始化为 null 并且只删除一次(也总是调用 new)。

我可能犯了一个相当明显的错误,但我不知道。任何建议都会很棒。(如果需要,我可以发布更多代码)。

编辑:

以下是代码结构的工作原理。

basePawn 是一个具有一些相当基本的方法来表示角色的类。

Controller 是一个类,其指针指向用作角色大脑(AI 或玩家控制)的 basePawn(最初设置为 NULL)。它包含一个 removePawn 方法。

void controller::removePawn()
{
    if (pawn != NULL)
    {
        cout << "Calling delete.\n";
        delete pawn;
        pawn = NULL;
    }
}

这个方法在析构函数中被调用。当pawn 从关卡中移除时,它也会被调用。

它还有一个重生方法。

if (pawn == NULL)
{
    respawnCounter++;

    if (respawnCounter >= respawnTime)
    {
        //Switch block to change class
        pawn = new basePawn;

        if (pawn !=NULL)
        {
            pawn->boardY = 4; //Will be random
            pawn->boardX = 5; //Will be random

            respawnCounter = 0;

            pawn->setIdle();

            return true;
        }
    }
}

编辑:

baseController 头文件

#ifndef _BASEPAWNCONTROLLER_H
#define _BASEPAWNCONTROLLER_H

#include "basePawn.h"
#include "textureManager.h"
#include "direction.h"
#include "vector2f.h"

//Used to control pawns
//Allows the same commands to be used to control different pawns
class basePawnController
{
private:
protected:
basePawn *pawn;

int respawnCounter,
    respawnTime;

vector2f    targetDest;

bool        bMoving,
            bTarget;

void        removePawn();

public:

bool    bFirstFrameDead;

basePawnController();
virtual ~basePawnController();

virtual void update();

basePawn *getPawn();
void setPawn(basePawn *p);  
void setTarget(float x, float y);
direction getDir();
bool isMoving();
bool hasTarget();

virtual bool respawn();
virtual void render(textureManager &tManager);

virtual bool wantsPawn();
virtual void giveTargetInfo(direction d, int n);
};

#endif
4

2 回答 2

1

鉴于它是 PS2,我将假设您无法访问 C++11 和它 - 智能指针(std::unique_ptr和排序)等。如果 Boost 或 C++11 不是一个选项,你真的应该采取时间并研究如何重新实现基本的智能指针功能——这将大大减轻精神压力。但是,让我们假设这不是一个选项。

请注意,这是最有可能发生的情况,因为从问题和评论中收集到的问题描述很少。

当控制器实例超出范围时,您试图通过释放资源(如 pawn)来利用 RAII,因为您调用removePawn了析构函数——这很好。但是,当您不提供非平凡的复制赋值运算符和复制构造函数实现与指针和堆分配相结合时,类的实例可能会以多种方式丢失数据/崩溃。

您应该真正实现额外的功能来管理可能以您不期望的方式发生的复制。如果您不自己管理它,代码可能会运行几次,并通过将控制器传递给函数或类似的方法让控制器以某种方式被复制——它将用旧控制器的数据构造一个新控制器。但这是一个浅拷贝,我们假设有效的 basePawn 的地址将被复制,但它不会将垂死实例的地址设置为0/ NULL

在旧的超出范围后,它的析构函数被调用。而且由于您没有使旧指针无效,因此它将删除现在由两个不同对象引用的同一个pawn。当您delete pawn;稍后声明时- 繁荣。

您需要正确实施这两个:

basePawnController(basePawnController& that);
basePawnController& operator=(basePawnController& that);

不要陷入将其声明为的陷阱,const当您使用原始指针时,这不是一个选择。需要发生的事情是这样的,您可以根据另一个实现一个:

// Copy constructor
basePawnController::basePawnController(basePawnController& rhs) {

    *this = rhs; // invokes basePawnController::operator=()

}

// Copy assignment operator
basePawnController& basePawnController::operator=(basePawnController& rhs) {

    // copy your stuff and now the basePawn
    pawn = rhs.pawn; // Copy the address...
    rhs.pawn = 0; // ...but make sure the old instance doesn't troll you.

    return *this;

}

我对您的最佳建议是利用 RAII 设施通过智能指针调查所有权透明度。编程应该是一种乐趣。

于 2013-04-29T19:19:31.240 回答
0

嗯,你们说的很对。

添加复制构造函数和赋值运算符后,我执行了更多检查以查看问题实际发生在哪里。事实证明,这与我的控制器类没有任何关系,而是与我的 pawn 和 world 类有关。

我的pawn 有一个damageNode* 向量,我没有删除它。这不是一个大问题,因为我在世界上有一个指向它们的指针。但是我也从未在世界级中删除它们,因此在删除典当和世界时我遇到了段错误。

于 2013-05-02T10:59:11.483 回答