我有三个类:房间、门和世界
#include <set>;
using namespace std;
class Door; // Forward declaration
class Room {
public:
Door* door1;
Door* door2;
Room(){}
~Room() {
delete door1;
door1 = 0;
delete door2;
door2 = 0;
}
};
class Door {
public:
Room* roomA;
Room* roomB;
Door(Room* roomA, Room* roomB) {
this->roomA = roomA;
this->roomB = roomB;
linkRooms(); // This sets up the Door-Pointers in the Rooms
// so they know about the new door.
}
~Door() {
// Returns the room-owned pointer pointing at this door
getMyRoomPointer(roomA) = 0;
getMyRoomPointer(roomB) = 0;
}
Door * & getMyRoomPointer(Room * const & room) {
if (room->door1 == this) return room->door1;
else return room->door2;
}
void linkRooms() {
roomA->door1 = this;
roomB->door2 = this;
}
};
class World {
public:
std::set<Room*> rooms;
World() {
// Set up two rooms and link them using a door
Room* newRoom = new Room();
rooms.insert(newRoom);
Room* anotherNewRoom = new Room();
rooms.insert(anotherNewRoom);
new Door(newRoom, anotherNewRoom);
}
~World() {
// Iterate over the rooms and call delete on all of them
for (std::set<Room*>::iterator it = rooms.begin(); it != rooms.end(); ++it) {
delete *it;
}
}
};
int main() {
World world;
return 0;
}
当运行 main 时,构造函数只用两个房间和一扇门填充世界,作为它们之间的链接。主要回归后,世界应该被删除,所有的房间和门也应该被照顾。
问题是,我的 Door 析构函数从未被调用过。因此,房间内的门指针未设置为空,当“另一边”的房间试图删除同一扇门时,我收到错误消息。
当我只是创建一个 Door 的实例,然后立即删除它时,我没有遇到任何问题:
int main(){
Room oneRoom;
Room anotherRoom;
Door* door = new Door(&oneRoom, &anotherRoom);
delete door; // works just fine
return 0;
}
问题:为什么不调用 Door 构造函数?是否允许像第一个示例中那样设置门?
我知道,我正在双重删除我房间的门指针,并且我可以(并且应该)使用 SmartPointers。现在我只是想知道为什么我要面对这种行为。毕竟,我对 C++ 还是个新手。
我现在确实设置了一个可运行的示例,它重现了错误。
您在定义Door
之前调用delete
。因此程序的行为是未定义的,不能保证调用析构函数。
引自标准(草案)[expr.delete] :
- If the object being deleted has incomplete class type at the point of deletion and the complete class has a non-trivial destructor or a deallocation function, the behavior is undefined.
解决方案:如果类型的析构函数是非平凡的(即用户定义的,例如 ~Door
,则在类型完成之前永远不要删除此类对象)。在这种情况下,在调用 delete 的函数之前定义 Door
。
作为一般规则,除非类类型完整,否则永远不能调用成员函数。不幸的是,对于析构函数,编译器可能并不总是能够捕获错误。附言。 g++ 会警告您的程序:warning: possible problem detected in invocation of delete operator: [-Wdelete-incomplete]
我是一名优秀的程序员,十分优秀!