使用虚拟析构函数 c++ 删除指向 class 的指针 (*&)
delete on pointer (*&) to base class with virtual destructor c++
所以,我在一个非常老的系统 (2006-2007) 上有一个游戏服务器 运行,它在玩家登录时创建一个玩家对象,在创建怪物时创建一个怪物对象,以及一个 npc当 npc 出现时对象。所有这些 classes 都派生自生物 class 并且它们都有虚析构函数。因此,当我创建这些对象时,我将它们添加到一个重载了 operator() 的生物向量(不是实际的 STL 向量,而是一个定制的模板)。我写了这个虚拟代码以方便显示。
vector<Creature *> CreatureList(100);
template <typename T>
struct vector {
vector(int InitialSize);
int InitialSize;
T& operator()(int i);
T* Entry; // At constructor, this is 'Entry = new T[InitialSize];' and is deleted at destructor.
};
struct Creature {
Creature();
virtual ~Creature();
bool IsOnMap;
char Name[30];
};
struct Player : Creature {
Player();
virtual ~Player();
int PlayerState;
int PlayerID;
};
struct Monster : Creature {
Monster();
virtual ~Monster();
int SpawnPosX, SpawnPosY;
int Health;
};
struct NPC : Creature {
NPC();
virtual ~NPC();
Object TradeChest;
int SpawnPosX, SpawnPosY;
};
int OnPlayerLogin() {
Player *pl = new Player;
CreatureList(NextCreatureID++) = pl;
return PlayerID;
}
void OnMonsterSpawn() {
Monster *mn = new Monster;
CreatureList(NextCreatureID++) = mn;
}
void OnNPCSpawn() {
NPC *npc = new NPC;
CreatureList(NextCreatureID++) = npc;
}
void ProcessAllCreatures() {
for (int i = 0; i < NextCreatureID; i++) {
Creature* cr = CrList(i); // this doesn't return Creature* but actually Creature*&
if (!cr)
continue;
if (!cr->IsOnMap)
delete cr; // This spits a SIGSEGV (Segmentation fault).
}
}
此虚拟代码假定所有初始化都是在构造函数中完成的。 NextCreatureID
只是一个用作索引的自动增量变量。自定义向量 class 只是一个可自动调整大小的数组,并且 operator() 将始终 return 对实际对象的引用(由于内部代码约定,这不能更改)。
问题是它向进程发送了一个 SIGSEGV,如果我尝试 delete &cr
,我会因为指针无效而收到 SIGABRT。那么,有没有什么办法可以解决这个问题而不必更改向量 class? (这对我来说是不可能的,因为 collab.work as I said)
if (!cr)
continue;
不会像您预期的那样工作。 delete
指针不会将其重置为 nullptr
。在您第一次调用 ProcessAllCreatures() 时,一切都可能正常,当您第二次调用它时,您将删除已删除的指针,因为您永远不会 continue
查看已删除的指针。
所以,我在一个非常老的系统 (2006-2007) 上有一个游戏服务器 运行,它在玩家登录时创建一个玩家对象,在创建怪物时创建一个怪物对象,以及一个 npc当 npc 出现时对象。所有这些 classes 都派生自生物 class 并且它们都有虚析构函数。因此,当我创建这些对象时,我将它们添加到一个重载了 operator() 的生物向量(不是实际的 STL 向量,而是一个定制的模板)。我写了这个虚拟代码以方便显示。
vector<Creature *> CreatureList(100);
template <typename T>
struct vector {
vector(int InitialSize);
int InitialSize;
T& operator()(int i);
T* Entry; // At constructor, this is 'Entry = new T[InitialSize];' and is deleted at destructor.
};
struct Creature {
Creature();
virtual ~Creature();
bool IsOnMap;
char Name[30];
};
struct Player : Creature {
Player();
virtual ~Player();
int PlayerState;
int PlayerID;
};
struct Monster : Creature {
Monster();
virtual ~Monster();
int SpawnPosX, SpawnPosY;
int Health;
};
struct NPC : Creature {
NPC();
virtual ~NPC();
Object TradeChest;
int SpawnPosX, SpawnPosY;
};
int OnPlayerLogin() {
Player *pl = new Player;
CreatureList(NextCreatureID++) = pl;
return PlayerID;
}
void OnMonsterSpawn() {
Monster *mn = new Monster;
CreatureList(NextCreatureID++) = mn;
}
void OnNPCSpawn() {
NPC *npc = new NPC;
CreatureList(NextCreatureID++) = npc;
}
void ProcessAllCreatures() {
for (int i = 0; i < NextCreatureID; i++) {
Creature* cr = CrList(i); // this doesn't return Creature* but actually Creature*&
if (!cr)
continue;
if (!cr->IsOnMap)
delete cr; // This spits a SIGSEGV (Segmentation fault).
}
}
此虚拟代码假定所有初始化都是在构造函数中完成的。 NextCreatureID
只是一个用作索引的自动增量变量。自定义向量 class 只是一个可自动调整大小的数组,并且 operator() 将始终 return 对实际对象的引用(由于内部代码约定,这不能更改)。
问题是它向进程发送了一个 SIGSEGV,如果我尝试 delete &cr
,我会因为指针无效而收到 SIGABRT。那么,有没有什么办法可以解决这个问题而不必更改向量 class? (这对我来说是不可能的,因为 collab.work as I said)
if (!cr)
continue;
不会像您预期的那样工作。 delete
指针不会将其重置为 nullptr
。在您第一次调用 ProcessAllCreatures() 时,一切都可能正常,当您第二次调用它时,您将删除已删除的指针,因为您永远不会 continue
查看已删除的指针。