说我有一个Person
类,并以name
,age
和bestFriend
作为属性。我对如何最好地代表bestFriend
感到困惑。多个Person
实例可以指向同一个bestFriend
,从而排除了unique_ptr
。并且也可能存在循环关系,从而排除了shared_ptr
。因此,在这种情况下使用weak_ptr
是否理想?我什至要在这里使用智能指针,而不仅仅是原始指针吗?
class Person {
std::string name;
int age;
std::weak_ptr<Person> bestFriend;
};
答案 0 :(得分:3)
指针(包括原始指针和智能指针)表示某些所有权。因此,要选择合适的指针,您需要确定所有权。如果某个东西拥有,那么如果这个东西死了,那么这个对象也必须死掉。如果我死了,我最好的朋友必须死吗?我不这么认为。因此,我没有拥有我最好的朋友。这排除了unique_ptr
和shared_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
预期用途的更多详细信息,因此上述建议是基于一些推测,实际上可能没有用,具体取决于您的实际情况意向。