我应该使用智能指针吗?

gli*_*ite 7 c++ pointers smart-pointers c++11

我有一个类如下:

class node
{
public:

     node* parent;
     std::list<node*> children;
};
Run Code Online (Sandbox Code Playgroud)

我应该使用智能指针而不是原始指针吗?为什么?如果是的话,什么样的智能指针?

Pup*_*ppy 16

无论您拥有哪些资源(内存,文件等),都要始终使用智能指针.手动拥有它们非常容易出错,并且违反了许多良好实践,例如DRY.

使用哪一个取决于您需要的所有权语义.unique_ptr最适合单一所有权和shared_ptr共享所有权.

由于孩子不拥有他们的父母,原始的父指针是好的.但是,如果父母拥​​有自己的孩子,那么unique_ptr这里工作效果最好.

还有一点值得注意的是,究竟什么链接指针?这是没有意义的.为什么不是一个价值链表?

  • @JamesKanze没有.就是不行 (8认同)
  • @JamesKanze _`使用unique_ptr几乎可以保证悬挂指针`_ - 我很难看到你的意思.你能指出一个例子吗? (5认同)
  • @JamesKanze:没问题.首先,您,实施者,不再需要手动删除节点.这**保证*你不能双重删除它们,或忘记删除它们,并保证异常安全.并且你得到*删除所有那些否则会删除的代码.因此它减少了代码大小并保证了安全性.这听起来像是我能想象到的各种方式的胜利.至于不同的指针类型,在C++中,您可以使用不同的类型来执行不同的工作.这是生活中必不可少的事实.语法清楚地表明了什么是什么. (4认同)
  • @JamesKanze:资源,比如......子节点的内存?而且,基于这个结构的`unique_ptr`版本比基于原始指针的版本更不可靠或更复杂.实际上,`unique_ptr`实际上是*可靠和简单的定义*.也许你应该扩展为什么你认为智能指针版本会比原始指针版本更糟糕. (3认同)
  • @JamesKanze:`unique_ptr`没有引入比'delete`更多的悬空指针.并且`shared_ptr`**仅在存在引用周期时引入内存泄漏 - 所有优秀设计*很少*具有,甚至非常糟糕的设计很少 - 并且没有比删除更多的悬空指针. (3认同)
  • @James:手动内存管理与'简单'相反. (3认同)
  • @JamesKanze:所以不要"从一个父节点移除节点,将其附加到另一个父节点"; 改为移动指针.指向该节点的任何其他指针仍然有效.删除节点的唯一原因是将其从树中删除,在这种情况下,对它的任何引用都无效(除非您需要更复杂的方案,但这里没有任何指示).对不起,但我真的看不到你的论点了,而不是"不要使用聪明的指针,因为如果你用错误的东西做错了,就会发生错误的事情"; 这可以适用于任何实践. (3认同)
  • @gliderkite:您没有表明共享所有权是必要的. (2认同)
  • @JamesKanze:没有额外的悬挂指针与独特的ptr.考虑像`template <typename T> void f(T*p){delete p; }`.你是否认为`f(p)`泄漏超过`delete p;`?当然不是.那么,为什么它有什么不同,如果,而不是`f`,我有`~unique_ptr`?关于何时擦除该项并删除指针是你的*选择,并且该选择恰好与你原本称为"删除ptr"的时间完全相同;如果你是手动管理它,那意味着它是不可能创建额外的悬空指针. (2认同)
  • @JamesKanze:列表是问题中的一个:`std :: list <node*> children`.我的假设是OP打算用它来管理孩子,否则他不会问是否使用智能指针.鉴于此,`unique_ptr`是正确的答案.如果你确实需要重新组织树,那么将它从一组孩子移动到另一组孩子就是一个简单的例子 - 我不知道你为什么认为"失败".如果您认为不同的所有权模型更合适,那么也许您应该写一个解释*为什么*智能指针"不起作用"和"应该避免"的答案. (2认同)
  • @JamesKanze:我完全没有看到使用`unique_ptr`以任何方式使用原始指针都不会导致悬挂指针,尽管你所有的神秘暗示都明显且不可避免.使用`unique_ptr`管理ad-hoc`delete`表达式的对象的优点如上所述:不需要编写析构函数,不需要`try ... catch` dance将它们放入容器中,并且没有意外复制或丢失应该代表对象所有权的指针的危险.这些是原始指针的常见问题,`unique_ptr`完全解决. (2认同)
  • @JamesKanze:好的,这整个论点只是对"复杂性"和"直觉"构成的意见的不同.我将坚持自动,异常安全的内存管理和明确定义的可转让所有权语义(对我而言,这完全是简单,直观和非特殊); 如果你愿意,你会坚持使用手动指针 - 玩杂耍.抱歉这么长时间 - 从你反复模糊的危险提示中,我想你可能知道使用`unique_ptr`的真正问题,这就是为什么我一直要求你详细说明. (2认同)

rod*_*igo 5

使用智能指针总是一个好主意,但要注意引用循环.

class node
{
public:
     std::weak_ptr<node> parent;
     std::list< std::shared_ptr<node> > children;
};
Run Code Online (Sandbox Code Playgroud)

这就是为什么首先存在的原因weak_ptr.请注意,他们不是那么聪明地检测循环,你必须手动完成,并使用weak_ptrs 打破它们.

  • 父指针不需要是非原始指针. (5认同)
  • 对于指针混淆,没有人能分辨出`shared_ptr <T>`,`unique_ptr <T>`和`T*`之间的区别应该真正编写生产C++.更不用说编译器可以方便地保护你免受*几乎*这些指针的所有使用错误 - 而不是你可以说的原始指针. (5认同)
  • @JamesKanze:要太晚捕捉它是不可能的.简单的`unique_ptr <T> x(新T(...))`场景非常防弹.即使对于函数参数,也存在通常的评估顺序欢闹,而且标准中遗漏了`make_unique`(被接受为缺陷),但是你可以编写自己的,即使在那种情况下也保证正确.至于太早,`unique_ptr`将不会释放,直到你,程序员,删除它.这发生在完全相同的时间,只需从列表中删除指针然后删除它. (3认同)
  • @JamesKanze:更复杂?它是`shared_ptr`的简单插入 - 当然比原始指针版本简单得多 - 对于`unique_ptr`来说简单``std :: move`.那里没有明显的复杂性.至于在将其移入树中后填充它,然后......只需在插入时给出非拥有的参考.这正是标准容器的行为,比如`std :: map`,它们运行得很好. (3认同)
  • @JamesKanze:可能,但不是特别可能,并且没有明确需要共享所有权,因此独特的所有权和原始指针是最简单的设计. (2认同)