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

时间:2019-01-06 22:58:33

标签: c++ c++11

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

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

2 个答案:

答案 0 :(得分:3)

指针(包括原始指针和智能指针)表示某些所有权。因此,要选择合适的指针,您需要确定所有权。如果某个东西拥有,那么如果这个东西死了,那么这个对象也必须死掉。如果我死了,我最好的朋友必须死吗?我不这么认为。因此,我没有拥有我最好的朋友。这排除了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存储给最好的朋友,那意味着一个人只有在成为某人的最好朋友的情况下才能存活...没错,但是在软件开发世界中,对不起。 / p>

答案 1 :(得分:2)

智能指针std::unique_ptr<>std::shared_ptr<>用于所指向对象的unique or shared ownership。对于您的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; }
};

话虽如此,您必须确保这些指针始终保持有效。为此,可以使用Person存储std::deque<Person>,这允许添加新的Person,而不会使任何现有的Person指针无效。但是,您不能删除没有使其他Person的指针无效的任意Person,因此与删除Person相比,最好将Person标记为已死(您可能还有其他所有生存清单) class Person个指针)。这样做的好处是可以避免晃动最好的朋友指针(但是您会得到死去的最好的朋友)。

警告。由于您未能提供有关sendAction预期用途的更多详细信息,因此上述建议是基于一些推测,实际上可能没有用,具体取决于您的实际情况意向。