8

这不是“如何做”的问题,而是“如何以正确的方式做”

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

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

问题是,我不太确定在这种情况下使用它们的“最佳方式”是什么……阅读智能指针后:或者谁拥有你的宝贝?我什么时候使用哪种指针?还有一些我得出了不同的结论:

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

现在我仍然只是使用我通过get()方法获得的原始指针,unique_ptr但这对我来说似乎有点缺陷。我仍然可以不小心在指针上调用 delete 并取消智能指针的好处。

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

我对这两种方式都不太满意。是否有一种干净(er)的方式来指向对象的unique_ptr子对象?还是我错过了解决此问题的完全不同且更好的方法?

4

4 回答 4

3

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

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

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

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

但是裸指针并没有那么糟糕。唯一的区别是它可以是nullptr,并且它在 namespace 内没有一个漂亮、长、显式的名称std

于 2013-08-27T02:06:44.793 回答
2

你想用 ashared_ptr代替你的unique_ptrandweak_ptr代替你的原始指针。这将给出你所追求的。'weak_ptr不会干扰已编辑对象删除基础对象的能力。

于 2013-08-27T01:51:40.523 回答
1

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

或者对于 QObjects:

  • QPointer(或者QWeakPointer,特别是在 Qt4 中)

或者实现copy-on-write数据共享,Qt容器和QString风格:

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

但最重要的是,不要使用std::unique_ptrstd::shared_ptr与有父对象的 QObjects 一起使用,因为如果父对象先删除子对象,则 std:: 指针将再次删除它,使程序崩溃(其他方式也可以,子对象会通知它的父对象它已被删除)。换句话说,如果混合 QObjects 和 std:: 指针,很可能会出现细微的错误,所以不要这样做。从您的问题中不清楚您是否正在这样做,以防万一。

于 2013-08-27T06:13:36.990 回答
0

有一个关于世界上最笨的智能指针的提议,它是一个非拥有指针。基本上,它的意思是T*“哦,顺便说一句,我对这些数据没有任何所有权”。

在这种情况下,您必须管理观察/被动/哑指针在unique_ptr消失时重置 - 半手动生命周期管理。T*使用带有表明它是非拥有的名称的原始文件与使用上述文件一样好。

执行上述操作有很多好处,尤其是当您拥有具有依赖生命周期的对象时。

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

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

(单线程问题是你验证它weak_ptr是好的,做一些导致shared_ptr重置的事情,然后继续想要使用weak_ptr的数据而不重新检查。天真地,它可以通过例外来避免,但在仔细检查后你会遇到您必须在访问之前编写所有方法以检查删除this并抛出 ifthis被删除的问题,这是一个非常苛刻的要求!)

于 2014-05-09T13:26:37.600 回答