Circular dependency with the relationships “contains” and “is in”

本小妞迷上赌 提交于 2019-12-22 13:52:46

问题


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

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.

My questions are:

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

2) Is this solution dirty/inelegant for you?

3) Is it worth changing to something else?


回答1:


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.

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;
};

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).

So instead, declare Person like this:

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

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

To dereference currentRoom, you can then do:

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

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>).

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

More about std::weak_ptr at cppreference.



来源:https://stackoverflow.com/questions/50665301/circular-dependency-with-the-relationships-contains-and-is-in

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!