如果存在任何循环关系,我应该假设弱指针使用吗?

Should I assume weak pointer usage if there is any cyclic relationship?

本文关键字:指针 假设 我应该 任何 存在 循环 关系 如果      更新时间:2023-10-16

假设我有一个Person类,nameagebestFriend作为属性。我对如何最好地代表bestFriend感到困惑.多个Person实例可以指向同一个bestFriend,这排除了unique_ptr。并且还有循环关系的可能性,排除了shared_ptr.那么,在这种情况下使用weak_ptr是理想的吗?我什至想在这里使用智能指针而不仅仅是原始指针吗?

class Person {
std::string name;
int age;
std::weak_ptr<Person> bestFriend;
};

指针(原始和智能)表示一定的所有权。因此,要选择合适的指针,您需要决定所有权。如果某物拥有一个物体,那么如果这个东西死了,那么这个物体也必须死。如果我死了,我最好的朋友必须死吗?我不这么认为。因此,我没有最好的朋友。这排除了unique_ptrshared_ptr,因为它们拥有智能指针。

所以我们有两个选择:weak_ptr或原始指针。这取决于您将如何跟踪活着的人。

最简单的方法可能是依靠智能指针来跟踪活着的人。这意味着,你对所有人都有一些shared_ptr存储,然后你存储weak_ptr以指向另一个人。在这种情况下,我知道如果我有一个朋友并且weak_ptr::lock()返回nullptr,这意味着我的朋友已经死了。方便,但不是很灵活。例如,想象一下,当一个人去世时,你需要给一个家庭写一封信。你什么时候会这样做?亲自的析构函数?这将是多种责任的混合。在shared_ptr<Person>的自定义删除器中?这会破坏封装,因为此自定义删除程序可能具有许多功能。

另一种方法是由专门的经理跟踪活着的人。同样,您需要一些所有人都居住的存储空间。您可以按价值或通过shared_ptr存储它们 - 由您决定。然后存储指向这些对象的原始指针。(注意:如果将它们存储在矢量中,哪个大小是要更改的对象,则存储指向它们的原始指针不是一个好主意,因为可能会重新分配)。在这种情况下,你无法通过查看原始指针来判断我最好的朋友是否还活着。我们需要检查经理以获取此信息。这更灵活,但我会说不太安全,因为我们的系统中内置了悬空指针。

我建议不要为了这个原因而存储原始指针,而是去存储一个ID。 存储人的ID,并按ID登记人员。这个注册表将处理所有混乱,并将正确检测情况,当有人想要访问死者时,触发邮递员向亲戚发出一封信等。这也允许区分我没有最好的朋友和我最好的朋友去世的情况。weak_ptr在这两种情况下都会返回nullptr

PS 如果我们shared_ptr存储给最好的朋友,那就意味着一个人只有在他是某人最好的朋友时才会活着......如此真实,但不是在软件开发领域,对不起。

智能指针std::unique_ptr<>std::shared_ptr<>用于所指向对象的唯一或共享所有权。在你的Person的情况下,这种所有权的概念几乎没有意义,最好的朋友大概最好用一个简单的原始(观察)指针来表示:

struct Person
{
std::string name;
date_type born, died=date_type::never;
const Person *bestFriend = nullptr;     // defaults to none
time_type age() const
{ died==date_type::never? date_type::today()-born : 0; }
};

话虽如此,您必须确保这些指针始终有效。为此,可以使用std::deque<Person>存储Person,该允许添加新的Person,而不会使任何现有的Person指针无效。但是,您不能删除任意Person,而不会使指向其他Person的指针无效,因此最好将Person标记为死,而不是删除它(您可能有另一个所有活动Person指针的列表)。这样做的好处是可以避免悬挂最好的朋友指针(但你会得到最好的朋友已经死了)。

警告。由于您未能提供有关class Person预期目的的更多详细信息,因此上述建议基于一些猜测,实际上可能没有用处,具体取决于您的实际意图。