成员函数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()
基本上是 north
、south
等指针的 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_room
和 another_room
实例,但是您向 connect()
传递了使用 make_shared()
在堆上创建的全新实例。让你的 example_room
和 another_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
。在示例代码中,它制作了两个原始房间的副本。这不是这里需要的。事实上,共享指针在这个应用程序中是错误的。将有几个房间属于该应用程序,它们应该在全局范围内或在管理它们生命周期的某种容器中定义。每个房间都应该有一个指向其邻居的普通指针。任何房间都不需要管理其邻居的生命周期。这是应用程序的责任。
我正在创建一个非常简单的游戏引擎,使用现代 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()
基本上是 north
、south
等指针的 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_room
和 another_room
实例,但是您向 connect()
传递了使用 make_shared()
在堆上创建的全新实例。让你的 example_room
和 another_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
。在示例代码中,它制作了两个原始房间的副本。这不是这里需要的。事实上,共享指针在这个应用程序中是错误的。将有几个房间属于该应用程序,它们应该在全局范围内或在管理它们生命周期的某种容器中定义。每个房间都应该有一个指向其邻居的普通指针。任何房间都不需要管理其邻居的生命周期。这是应用程序的责任。