C ++ 11非拥有引用/指向unique_ptr的指针?

时间:2013-08-27 01:19:57

标签: c++ pointers reference unique-ptr

这不是“怎么做”的问题,而是“如何正确地做到这一点”

我正在Qt中开发一个编辑器,其中不同的小部件显示子级及其(成员)变量。这些小部件中的每一个都应该包含一个指向已编辑子节点的引用/指针,以显示和更改其成员变量。

第一次尝试是旧的ANSI C方式,我学习了(并且仍然有点卡住)使用简单的原始指针指向已使用的对象。它工作正常,但由于C ++ 11标准支持智能指针,建议我使用它们。我想尝试使用它们。

问题是,我不太确定在这种情况下使用它们的“最佳方式”是什么...... 在阅读Smart Pointers: Or who owns you baby?Which kind of pointer do I use when?以及其他一些内容后,我得出了不同的结论:

第一种是使用*unique_ptr,因为编辑的对象显然是创建并删除其子对象的所有者。小部件只是指孩子显示或更改它们。 问题是如何将小部件引用给孩子...

现在我只是使用get() unique_ptr方法得到的原始指针,但这对我来说似乎有点瑕疵。 我仍然可以意外地在指针上调用delete并取消智能指针的好处。

第二种方法是使用shared_ptr,因为许多对象引用子对象并进行编辑。在一个小部件中意外删除它也不会有害,因为它仍归其他对象所有。 问题是他们拥有它。当我想从编辑过的对象中删除它时,我还必须发信号通知所有小部件,以便在它真正消失之前将其删除。 (这似乎又有缺陷且容易出错)

我对两种方式都不满意。是否有一种干净的(呃)方式指向对象的unique_ptr子节点?或者我错过了一个完全不同的更好的解决这个问题的方法?

4 个答案:

答案 0 :(得分:2)

您希望使用shared_ptr代替您的unique_ptrweak_ptr代替您的原始指针。这将完全给出您所追求的内容。 weak_ptr不会干扰编辑对象删除基础对象的能力。

答案 1 :(得分:2)

您的用例不会直接转换为需求(如果其他人在您编辑它时删除了小部件会怎么样?)但我会假设您不需要任何超出裸指针的内容。

标准库不提供任何严格的指针 - 观察者类。在观察员实体中:

  • 本机类型(T *
  • 的可空,可变指针
  • 本机类型(T &
  • 的不可空,不可变引用
  • 类类型(std::reference_wrapper<T>
  • 的非可空,可变引用/代理
  • 可管理对象的可空,自我验证,可变指针(std::weak_ptr<T>

如果你想要一个非可空的,可变的指向非托管对象的指针,这是一个相当合理的事情,你可以自己动手。

但裸体指针并不是那么糟糕。唯一的区别是它可以是nullptr,并且它在命名空间std中没有漂亮的,长的显式名称。

答案 2 :(得分:1)

如果您使用Qt,您可能会考虑使用Qt智能指针而不是std :: smart指针:

或QObjects:

  • QPointer(或QWeakPointer,esp in Qt4)

或实现copy-on-write数据共享,Qt容器和QString样式:

还有其他指针类,但上面的一些最有可能做你想要的。同样重要的是,如果你有Qt容器类中的数据,QStrings等,它们使用写时复制语义处理它们自己的内存,并且通常应作为普通值(有时作为引用)传递而不是指针。

但最重要的是,不要将std::unique_ptrstd::shared_ptr与具有父项的QObjects一起使用,因为如果父项先删除子项,那么std :: pointer会再次将其删除,从而导致程序崩溃(其他方式将正常工作,孩子将通知它的父母,它被删除)。换句话说,如果混合QObjects和std :: pointers,很有可能出现细微的错误,所以就这样做吧。你的问题不清楚你是否这样做,以防万一。

答案 3 :(得分:0)

有一个world's dumbest smart pointer的提案,它是一个非拥有指针。基本上,它是T*表示&#34;哦,顺便说一句,我不会声明对此数据的任何所有权&#34;。

在这种情况下,如果unique_ptr消失,你必须管理观察/被动/哑指针被重置 - 半手动生命周期管理。使用带有名称的原始T*表明它是非拥有的,在使用上述内容之前也同样有效。

执行上述操作会有好处,尤其是当您拥有具有相关生命周期的对象时。

如果不这样做,则shared_ptrweak_ptr有效。但请注意,拥有weak_ptr的任何人都可以创建新的shared_ptr,这可以将共享对象的生命周期延长到原始shared_ptr之外。这必须发生,因为除了竞争条件,weak_ptr的用户确保其数据有效,然后去使用它,但在他们做shared_ptr的数据之前破坏。

因此weak_ptr必须能够阻止shared_ptr被破坏(在多线程上下文中阻塞,导致它失败&#34;以某种方式在单线程上下文中)。 &#34;故障&#34;在这种情况下,包括延长生命周期,这解决了多线程和单线程问题。

(单线程问题是您确认weak_ptr是好的,做一些导致shared_ptr重置的事情,然后继续想要使用weak_ptr&#39;没有重新检查的数据。天真地,可以通过例外来避免这种情况,但是经过仔细检查会遇到问题,在访问this之前必须对所有方法进行编码以检查删除,并抛出{{1删除,这是一个非常苛刻的要求!)