关系“包含"的循环依赖和“在" [英] Circular dependency with the relationships "contains" and "is in"
问题描述
我想就以下问题征求您的意见.
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
被销毁时,Person
s 也被销毁(繁荣!)所以不会出错.
This question needs really to be studied in context. If Person
s only exist in the context of a Room
then the back-pointer is safe. When a Room
is destroyed then the Person
s 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
.
在 cppreference中有关 std::weak_ptr
的更多信息一>.
More about std::weak_ptr
at cppreference.
这篇关于关系“包含"的循环依赖和“在"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!