编辑:
我已经实现了复制构造函数(两者都来自建议的答案)。我在我的控制器类中完成了这个,以及它的子类中的等效版本。但是,这还没有解决问题。此外,removePawn()
函数中的计数器和控制台注释(调用程序中唯一被删除的位置)显示它只被调用一次。
更详细地说,每个子类(不是指针)都有一个实例。这些在我的world
课程中声明。两者都通过world
类指针用作相同baseController
类方法中的参数。问题是,虽然两个进程都以相同的顺序进行相同的进程,但如果一个类有removePawn()
调用它,程序就可以了,并且会不断运行。但是,如果第二个类调用了removePawn()
(具体删除),它会在该指令处崩溃程序。
我还查了一下地址。分配后指针的地址与删除时的地址相同。
更多信息:关闭程序时,如果玩家被杀死(删除然后给予新的棋子),我将收到分段错误。但是,如果程序启动然后关闭而没有超过第一个新的和最后一个删除,那么它运行完全正常。
原件:
我在使用指针时遇到了一些麻烦。我理解他们并且相信我的代码非常强大,但是在调用这段代码时我似乎完全崩溃了。
Pawn是一个basePawn *,初始化为NULL。
if (pawn != NULL)
{
cout << "Calling delete.\n";
delete pawn;
pawn = NULL;
}
这是PS2程序的大学作业,所以我的调试仅限于控制台的基本打印。
删除删除行允许主要的new / delete部分运行几次,但它最终也会崩溃(我认为这是因为达到了内存限制,但我无法确定)
我检查了所有常见的罪魁祸首,指针初始化为null并且只删除一次(new也总是被调用)。
我可能犯了一个相当明显的错误,但我不知道。任何建议都会很棒。 (如果需要,我可以发布更多代码)。
编辑:
以下是代码结构的工作原理。
basePawn是一个类,其中包含一些代表角色的基本方法。
Controller是一个带有指向basePawn(最初设置为NULL)的指针的类,用作角色的大脑(AI或玩家控制)。它包含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
答案 0 :(得分: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设施通过智能指针调查所有权透明度。编程应该是一种乐趣。
答案 1 :(得分:0)
嗯,你们几乎是对的。
在添加复制构造函数和赋值运算符之后,我执行了更多检查以查看我的问题实际发生的位置。事实证明,这与我的控制器类没有直接关系,而是我的典当和世界类。
我的pawn有一个damageNode *的向量,我没有删除。这不是一个大问题,因为我在世界上有一个指针。但是我从来没有在世界级中删除它们,因此在移除棋子和世界时我遇到了seg错误。