在这种特殊情况下,应该传递指针或非常数引用吗

Should a pointer or a non-const reference be passed in this particular case?

本文关键字:指针 非常 引用 特殊情况下      更新时间:2023-10-16

假设类:

struct SimplifiedContainer {
    void add(Node *n); // the key is computed based on `n`
    std::map<int, Node*> myMap;
};

问题集中在add函数成员上,它向容器添加了一个节点。该函数采用非智能指针,因为节点由另一个容器所有。问题是:add应该取Node&吗?

永远不应该做的一件事是获取引用,只获取它的地址并将其存储在容器中。你不应该这样做的原因有很多。由于你不能按原样直接将引用存储在容器中(是的,你可以用std::ref将它们包装起来,它只会获取它们的指针,但它是非透明的,我看到人们不理解引擎盖下发生了什么),你的接口只剩下指针或类似指针的对象。

现在,冒着被否决的危险,我个人的建议是坚持你所拥有的。我认为那里没有问题。您有一个管理指针的实体,并且有一个指向管理容器的索引。与其让它成为shared_ptr(以及与shared_ptr管理相关的性能问题的开放代码,以及应用程序开发人员绞尽脑汁试图理解指针的生命周期),不如让它保持原样。当然,你必须确保索引始终与主容器同步,但如果你不确保这一点,您将面临比指针管理不善或悬空更大的问题。

编辑我将列出几个原因,为什么参考地址转换是不明智的。首先,operator &可以过载并返回其他内容。虽然这是一件可怕的事情,但人们仍然会这样做——所以你的界面可能会因此而崩溃。其次,当函数接受指针时,任何一个调用它的优秀程序员都会验证指针是如何使用的(这就是为什么你应该提供注释,指示函数存储指针,但不管理它)。通过这种方式,开发人员将知道给您的函数赋予什么。但是接受引用的函数不那么可疑,所以程序员会很乐意给它任何东西,包括局部变量。一般的理解是,如果你接受了一个推荐人,你就会发现有任何推荐人。

我的建议:

该函数采用非智能指针,因为节点由另一个容器所有

这不是不使用智能指针的理由
事实上,这是使用智能指针的一个很好的理由。

如果你的"另一个容器"没有存储智能指针,它应该是(特别是std::shared_ptr)。

在这种特殊情况下,应该传递指针还是非常数引用?

两者都没有。

接受并存储std::weak_ptr


我的回答是:

您已设置将std::unique_ptr存储在拥有容器中,并避开非拥有容器的智能指针安全性。

因此,我建议你坚持使用指针:

  • 对于对称性
  • 因为您将存储指针(不能[直接]将引用存储在容器中),因此接受指针到执行该存储的例程中"感觉"是正确的,并且
  • 因为它强烈地表明你正在自己实现内存管理(因为你对容器各自寿命的保证来自你的大脑/文档/希望/梦想,而不是实际的C++范围规则)
  • 引用最好用作不必存在很长时间的透明别名,通常是为了方便,很少用作逻辑句柄

然而,这完全是主观的,归根结底是风格观点。

这取决于情况。如果SimplifiedContainer拥有节点,则您应该收到一个std::unique_ptr。要确定它是否是所有者,只需检查谁负责删除节点即可。委托人通常是所有者。

如果SimplifiedContainer不是所有者,那么您可以在add中接收引用并将指针插入列表中。然而,您的类对于悬空指针是不安全的。

对于这种容器,最好的模式是实现一个container_view(这正是你想要做的!),它是一个容器的非拥有视图。如果是这样的话,您可以包含一个reference_wrapper的列表,您可以在这个页面上看到正在运行的模式