不调用 C++ 析构函数

标签 c++ destructor dynamic-allocation

我有三个类:房间、门和世界

#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] :

  1. 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]

关于不调用 C++ 析构函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41120443/

相关文章:

C++ 强制使用 unique_ptr 进行动态分配?

c - 分配指向 char 指针的指针的问题

c++ - 如何在 C++ 中创建动态分配的二维结构数组?

c++ - 文件名后的 Clang 关键字

c++ - 带有多个括号的宏

c++ - thread_local 变量何时以及如何初始化和销毁​​?

c++ - C++基于范围的for循环会调用迭代器的析构函数吗?

php - 在析构函数中使私有(private)变量为空有什么意义?

C++ 如何将整数和长整型转换为 char 数组

c++ - 如何将结构传递到 Matlab 中重新集成的自动生成的 C++ 代码中