为什么官方的Qt例子和教程不使用智能指针?

为什么关于Qt库的官方示例和教程从来没有使用智能指针? 我只看到newdelete创build和销毁小部件。

我search了基本原理,但是找不到它,除了出于历史原因或向后兼容性之外,我没有看到它自己。不是每个人都希望程序在widget构造函数失败时终止,并通过try / catch块是丑陋的(即使在less数地方使用)。 家长小部件可能拥有孩子的所有权也只是部分地解释了我的事情,因为您仍然必须在某个级别上使用delete父母。

因为Qt依靠父母 – 孩子模型来pipe理Qobject资源。 它遵循复合+责任链模式,从事件pipe理到内存pipe理,绘图,文件处理等使用。

实际上,试图在一个共享的\ unique指针中使用一个QObject 就是过度工程 (99%的时间)。

  1. 您必须提供将调用deleteLater的自定义删除程序
  2. 你父母的qobject已经在父对象中有一个引用。 所以你知道,一个对象不会泄漏,只要父母存在。 当你需要摆脱它,你可以直接调用deleteLater
  3. 没有父对象的 QWidget已经在Qapplication对象中有一个引用 。 和第二点一样。

这就是说,你仍然可以用Qt来使用RAII。 例如QPointer在QObject上performance为弱引用。 我会使用QPointer<QWidget>而不是QWidget*

注意:不要太迷人,两个字:Qt + valgrind。

智能指向儿童

智能指针类std::unique_ptrstd::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的编译器。 newdelete保证存在于早期的标准中。

但是,如果你有支持使用智能指针,我会鼓励通过原始指针来使用它们。

除了@Jamey所说的:

如果你巧妙地devise它,你可能永远不必在小部件上使用删除。 比方说,你有一个主窗口,你正在创build一个自动对象,并在事件循环中运行该窗口。 现在rest在这个小部件中的所有项目都可以添加为其子项目。 而且,由于您是直接/间接地将它们添加到此MainWindow中,所以当您closures此主窗口时,所有内容都将自动处理。 只需要确保您创build的所有dynamic对象/小部件都是MainWindow的子/孙子。 因此不需要明确删除..

  • QObject有一个父级定义和程序的树状结构允许相当有效地pipe理内存。

  • Qt中的dynamic打破了这个不错的理想,例如传递一个原始指针。 人们可以很容易地拿着一个dangling pointer ,但这是编程中的一个常见问题。

  • Qt智能指针,实际上是一个弱引用,是QPointer<T>
    并提供一些STL糖果。

  • 也可以和std::unique_ptr等混合使用,但是它只能用于程序中的非Qt机器。