关系“包含"的循环依赖和“在" [英] Circular dependency with the relationships "contains" and "is in"

查看:26
本文介绍了关系“包含"的循环依赖和“在"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想就以下问题征求您的意见.

I would like to gather opinion from you about the following problem.

我们有一个名为房间"的课程.每个房间可能包含零个或多个人"类的实例,因此房间存储人的集合(例如向量).它拥有他们.但是,在 Room 之间移动 Person 有一些耗时的逻辑,因此 Person 还包含他们所在的当前 Room.它只是一个没有所有权的指针.这个信息理论上是多余的,因为可以从房间里的人的集合中推导出来,但是假设房间数量很多>>人的数量,这样的操作会很慢......

We have a class called "Room". Each room may contain zero or more instances of a class "Person", so the Room stores a collection of Persons (e.g. vector). It owns them. However, there is some time-consuming logic related to moving Persons between Rooms, so the Person also contains current Room they are in. It is just a pointer without ownership. This information is theoretically redundant, because one could derive it from the collections of Persons in rooms, but assuming large number of rooms >> number of people, such an operation would be slow...

class Room {
std::vector<Person> peopleInside;
};

class Person {
Room* currentRoom; //could be shared_ptr to avoid raw pointers
};

当然,它更复杂(类比这更多)但我已经尽可能地简化了.

Naturally, it is more complex (classes have more than this) but I have simplified it as much as possible.

我的问题是:

1) 在这种情况下,这本身是一种循环依赖吗?

1) In this situation, is this a circular dependency per se?

2) 这个解决方案对你来说脏/不雅吗?

2) Is this solution dirty/inelegant for you?

3) 换别的东西值得吗?

3) Is it worth changing to something else?

推荐答案

这个问题确实需要结合上下文来研究.如果 Person 只存在于 Room 的上下文中,那么后向指针是安全的.当一个 Room 被销毁时,Persons 也被销毁(繁荣!)所以不会出错.

This question needs really to be studied in context. If Persons only exist in the context of a Room then the back-pointer is safe. When a Room is destroyed then the Persons are destroyed too (boom!) so nothing can go wrong.

但我怀疑这太简单了.Room 的声明更有可能是这样的:

But I suspect that's too simplistic. The declaration of Room is more likely to be something like:

class Room {
    std::vector<std::shared_ptr<Person>> peopleInside;
};

现在我们有一个可能的悬空指针"问题,您无法使用 Person 中的 std::shared_pointer<Room> 解决该问题,因为那时您 do 有一个循环依赖,并且 shared_ptr 都不能删除它正在管理的对象(因为 Room 持有对 Person 反之亦然,所以,死锁).

And now we have a possible 'dangling pointer' problem, which you can't solve with a std::shared_pointer<Room> in Person because then you do have a circular dependency and neither shared_ptr will ever be able to delete the object it is managing (because Room holds a reference to Person and vice versa, so, deadlock).

所以相反,像这样声明Person:

So instead, declare Person like this:

class Person {
    std::weak_ptr<Room> currentRoom;
};

并从一些 shared_ptr 初始化 currentRoom,当该 Room 存在时,您保持可用.这打破了循环依赖.

And initialise currentRoom from some shared_ptr<Room> that you keep available while that Room exist. This breaks the circular dependency.

要取消引用 currentRoom,您可以执行以下操作:

To dereference currentRoom, you can then do:

if (auto room_I_am_currently_in = currentRoom.lock())
{
    room_I_am_currently_in->OpenDoor ();
}

如果原来的 shared_ptr 被破坏了,那么 lock 就会失效.当 room_I_am_currently_in 超出范围(它实际上是一个 shared_ptr)时,锁将被释放.

And if the original shared_ptr<Room> has been destroed then lock will fail. The lock will be released when room_I_am_currently_in goes out of scope (it's actually a shared_ptr<Room>).

要将一个人移动到另一个房间,只需重新分配 currentRoom.

And to move a person to another room, just reassign currentRoom.

cppreferencestd::weak_ptr 的更多信息一>.

More about std::weak_ptr at cppreference.

这篇关于关系“包含"的循环依赖和“在"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆