成员函数returns 错误的智能指针

Member Function returns wrong smart pointer

我正在创建一个非常简单的游戏引擎,使用现代 C++ 以旧的基于文本的冒险风格。

我有这样的房间class:

class Room
{
public:
    Room(void);
    void connect(shared_ptr<Room> room, Direction direction);

private:
    std::shared_ptr<Room> north;
    std::shared_ptr<Room> south;
    std::shared_ptr<Room> east;
    std::shared_ptr<Room> west;
};

connect() 基本上是 northsouth 等指针的 setter。 它看起来像这样:

void Room::connect(std::shared_ptr<Room> room, Direction direction)
{
    switch (direction)
    {
        case Direction::NORTH:
            this->north = room;
            break;
        case Direction::SOUTH:
            this->south = room;
            break;
        case Direction::EAST:
            this->east = room;
            break;
        case Direction::WEST:
            this->west = room;
            break;
        default:
            std::cerr << "[ERROR] Invalid direction" << std::endl;
    }
}

现在我可以打电话给

Room example_room{};
Room another_room{};

example_room.connect(std::make_shared<Room>(another_room), Direction::NORTH)
another_room.connect(std::make_shared<Room>(example_room), Direction::SOUTH)

当我启动 lldb 并查看变量时,example_room::north 将是一个指向 Room 对象的 std::shared_ptr<Room>,但是,这个对象不是似乎是 another_room,因为它的 south 数据成员是一个包含 nullptr.

std::shared_ptr

所以他们指向其他房间,但他们不指向对方。我知道原因一定在 connect() 成员函数的某个地方,但我不知道在哪里。

您正在堆栈上创建 example_roomanother_room 实例,但是您向 connect() 传递了使用 make_shared() 在堆上创建的全新实例。让你的 example_roomanother_room 成为 shared_ptr 会起作用 但是! 正如@PiotrSkotnicki 在评论中提到的,你不应该使用 shared_ptr 用于循环依赖。改为对 Room 成员使用 weak_ptr

例如:

class Room
{
public:
    // ...
    void connect(weak_ptr<Room> room, Direction direction);
private:
    std::weak_ptr<Room> north;
    std::weak_ptr<Room> south;
    // ...
}

然后:

auto example_room = std::make_shared<Room>();
auto another_room = std::make_shared<Room>();

example_room->connect(another_room, Direction::NORTH)
another_room->connect(example_room, Direction::SOUTH)

只需确保在需要这些链接时保持原始 shared_ptr 有效。

make_shared 根据调用它的参数创建一个新对象,returns 一个指向新对象的 shared_ptr。在示例代码中,它制作了两个原始房间的副本。这不是这里需要的。事实上,共享指针在这个应用程序中是错误的。将有几个房间属于该应用程序,它们应该在全局范围内或在管理它们生命周期的某种容器中定义。每个房间都应该有一个指向其邻居的普通指针。任何房间都不需要管理其邻居的生命周期。这是应用程序的责任。