这是我试图为C++最佳实践解决的一个更一般的问题。假设我想创建存储相互引用的对象,比如图。所有对象都归同一对象所有,就像所有节点的Graph对象一样,也就是说所有权是固定的。
我的想法是:Graph类有一个节点的std::vector
,每个节点有一个表示其连接列表的节点的std::vector
。我想知道如何在智能指针方面最好地实现这一点?据我所知,所有权是唯一的,所以Graph向量应该是std::vector<std::unique_ptr<Node>> nodes
,我可以根据需要填充它。但是对于connections
向量,如何让每个节点存储对其连接的引用?这些只是只读引用,也许最好命名所有节点并只存储名称,或者将连接存储在Graph中。但是有没有一种好的方法可以将对连接节点的引用存储为常量指针?
注意:这实际上是关于所有权和智能指针,而不是关于数据结构,图形示例只是一个示例。
当讨论"最佳实践";,重要的是要考虑代码的质量属性和需求。
不存在";右";或";错误的";在诸如Graph
的代码的示例中回答;有不同程度的方法以不同的方式解决不同的问题,这在很大程度上取决于它的使用方式。
到目前为止,解决此类问题的最简单方法是主容器(Graph
(在具有unique_ptr
的中具有强所有权,并且仅使用原始指针(例如:(查看内部元素(Node
(中的生存期
class Graph
{
...
private:
std::vector<std::unique_ptr<Node>> m_nodes;
};
class Node
{
...
private:
std::vector<const Node*> m_connected_nodes;
};
这将很好地工作,因为Node
不能使其连接的节点发生突变,并且Graph
假设Node
永远不会超过它
但是如果您希望Node
的寿命比Graph
长,或者如果您希望在多个Graph
对象中使用Node
,则这种方法不起作用。如果它位于不同的Graph
之间,那么您可能会遇到Node
引用悬挂指针的风险——这将是糟糕的。
如果是这种情况,您可能需要考虑不同的所有权模式,例如shared_ptr
和weak_ptr
所有权:
class Graph
{
...
private:
std::vector<std::shared_ptr<Node>> m_nodes;
};
class Node
{
...
private:
std::vector<std::weak_ptr<const Node*>> m_connected_nodes;
};
在这种情况下,Node
只微弱地知道其他Node
对象,而Graph
是它们的强所有者。这防止了悬空问题,但现在shared_ptr
的控制节点以及在访问weak_ptr
节点之前必须检查其是否处于活动状态会带来额外的开销。
所以正确的答案是:这取决于。如果你能摆脱前一种方法,那可能是最干净的;您总是有一个所有者,因此逻辑简单易用。
我想知道如何在智能指针方面最好地实现这一点?
不使用它们。为图形使用节点向量:std::vector<Node>
。这是一个合理的默认选择,除非你有充分的理由这样做。
但是有没有一种好的方法可以将对连接节点的引用存储为常量指针?
是。Const指针是一种很好的存储方式,就好像它们是Const指针一样。(通过"const指针",我想我们实际上是在谈论指针到const(。
引用包装器是另一种选择。尽管它的优点是没有null的表示,但它也有语法笨拙的缺点。