为什么官方的Qt例子和教程不使用智能指针?
为什么关于Qt库的官方示例和教程从来没有使用智能指针? 我只看到new
和delete
创build和销毁小部件。
我search了基本原理,但是找不到它,除了出于历史原因或向后兼容性之外,我没有看到它自己。不是每个人都希望程序在widget构造函数失败时终止,并通过try / catch块是丑陋的(即使在less数地方使用)。 家长小部件可能拥有孩子的所有权也只是部分地解释了我的事情,因为您仍然必须在某个级别上使用delete
父母。
因为Qt依靠父母 – 孩子模型来pipe理Qobject资源。 它遵循复合+责任链模式,从事件pipe理到内存pipe理,绘图,文件处理等使用。
实际上,试图在一个共享的\ unique指针中使用一个QObject 就是过度工程 (99%的时间)。
- 您必须提供将调用deleteLater的自定义删除程序
- 你父母的qobject已经在父对象中有一个引用。 所以你知道,一个对象不会泄漏,只要父母存在。 当你需要摆脱它,你可以直接调用
deleteLater
。 - 没有父对象的 QWidget已经在Qapplication对象中有一个引用 。 和第二点一样。
这就是说,你仍然可以用Qt来使用RAII。 例如QPointer在QObject
上performance为弱引用。 我会使用QPointer<QWidget>
而不是QWidget*
。
注意:不要太迷人,两个字:Qt + valgrind。
智能指向儿童
智能指针类std::unique_ptr
和std::shared_ptr
用于内存pipe理。 有这样一个聪明的指针意味着,你拥有指针。 但是,当使用QObject
父项创buildQObject
或派生types时,所有权(清理责任)将交给父QObject
。 在这种情况下,标准库智能指针是不必要的,甚至是危险的,因为它们可能会导致双重删除。 哎呀!
生孤儿的指针
但是,当一个QObject
(或派生types)在堆上创build而没有父对象时,情况就大不相同了。 在这种情况下,你不应该只保存一个原始指针,而是一个智能指针,最好是一个std::unique_ptr
对象。 这样你就可以获得资源安全。 如果稍后将对象所有权交给父对象,则可以使用std::unique_ptr<T>::release()
,如下所示:
auto obj = std::make_unique<MyObject>(); // ... do some stuff that might throw ... QObject parentObject; obj->setParent( &parentObject ); obj.release();
如果在给父母抛出一个exception之前你做的事情会抛出一个exception,那么如果你使用了原始指针来保存这个对象的话,你将会发生内存泄漏。 但是,上面的代码是防止这种泄漏。
在更一般的说明
这不是现代的C ++build议,以避免原始指针在一起,但避免拥有原始指针。 我可能会添加另一个现代C ++的build议: 不要使用智能指针为其他程序实体拥有的对象。
您已经回答了您自己的问题: except if it's for historic reasons/backward compatibility
。 一个和QT一样庞大的库不能假设每个使用库的人都有支持C ++ 11的编译器。 new
和delete
保证存在于早期的标准中。
但是,如果你有支持使用智能指针,我会鼓励通过原始指针来使用它们。
除了@Jamey所说的:
如果你巧妙地devise它,你可能永远不必在小部件上使用删除。 比方说,你有一个主窗口,你正在创build一个自动对象,并在事件循环中运行该窗口。 现在rest在这个小部件中的所有项目都可以添加为其子项目。 而且,由于您是直接/间接地将它们添加到此MainWindow中,所以当您closures此主窗口时,所有内容都将自动处理。 只需要确保您创build的所有dynamic对象/小部件都是MainWindow的子/孙子。 因此不需要明确删除..
-
QObject
有一个父级定义和程序的树状结构允许相当有效地pipe理内存。 -
Qt中的dynamic打破了这个不错的理想,例如传递一个原始指针。 人们可以很容易地拿着一个
dangling pointer
,但这是编程中的一个常见问题。 -
Qt智能指针,实际上是一个弱引用,是
QPointer<T>
并提供一些STL糖果。 -
也可以和
std::unique_ptr
等混合使用,但是它只能用于程序中的非Qt机器。