new
和delete
来创建和销毁小部件。我搜索了理由,但没有找到,除非是出于历史原因或向后兼容性:并非每个人都希望程序在窗口小部件构造失败时终止,并且通过try/catch块处理这种情况只是丑陋的(即使在少数地方使用)。父窗口小部件可能接管子项的所有权也只是部分地解释了这个问题,因为你仍然必须在某个级别上使用
delete
来删除父窗口小部件。因为Qt依赖于父子模型来管理Qobject资源。它遵循复合+责任链模式,从事件管理到内存管理、绘图、文件处理等等都使用该模式...
实际上,在共享/独占指针中使用QObject是一种过度设计(99%的情况下)。
deleteLater
。话虽如此,你仍然可以使用RAII与Qt。例如QPointer行为类似于QObject
的弱引用。我会使用QPointer<QWidget>
而不是QWidget*
。
deleteLater
而不是简单地删除该对象?我经常使用智能指针来管理QObject派生类的实例,因此我之前搜索过答案,以确保我没有做危险的事情,据我所知,文档并未表明通常删除QObject指针是错误的(即使它由父对象拥有,因为析构函数将删除父对象的引用)。 - Kyle StrandQThread
中删除了一个 QObject
。QObject
的析构函数会自动断开所有与其相关的信号,并从其事件队列中删除挂起的事件。因此,如果您在其线程内部调用 delete
,那么这是可以的。话虽如此,使用 deleteLater()
几乎不可能出错,除非您有某种原因需要立即清理。 - Ralph Tandetzkystd::unique_ptr
和std::shared_ptr
是用于内存管理的智能指针类。拥有这样的智能指针意味着您拥有该指针。然而,当使用带有QObject
父级的QObject
或派生类型创建对象时,所有权(清理的责任)会移交给父级QObject
。在这种情况下,标准库的智能指针是不必要的,甚至是危险的,因为它们可能导致双重删除。糟糕!
然而,当在堆上创建一个没有父级QObject
的QObject
(或派生类型)时,情况就非常不同了。在这种情况下,您不应只持有裸指针,而应持有智能指针,最好是一个指向该对象的std::unique_ptr
。这样可以确保资源的安全性。如果稍后将对象所有权移交给父级QObject
,则可以使用std::unique_ptr<T>::release()
,如下所示:
auto obj = std::make_unique<MyObject>();
// ... do some stuff that might throw ...
QObject parentObject;
obj->setParent( &parentObject );
obj.release();
如果在给您的孤儿分配父项之前执行的操作引发异常,且您使用原始指针来持有该对象,则会出现内存泄漏。但是上面的代码可以避免这种泄漏。
现代C++建议不完全避免使用原始指针,而是避免持有原始指针。我可能还要添加另一个现代C++建议:不要为某些其他程序实体拥有的对象使用智能指针。
除非出于历史原因/向后兼容性
。像QT这样庞大的库无法假设每个使用库的人都有支持C++11的编译器。new
和delete
在早期标准中是有保证存在的。
然而,如果你确实有支持使用智能指针的能力,我鼓励你使用它们而不是裸指针。
auto_ptr
,那么不使用它是正确的决定。在C++11之前没有好的标准化智能指针。 - Zyx 2000QSharedPointer
和QScopedPointer
。 - Ruslan除了@Jamey所说的:
如果您巧妙地设计,您可能永远不需要在小部件上使用delete。 假设您有一个主窗口,并创建了一个自动对象,并在事件循环中运行该窗口。 现在,将此小部件的所有其他项添加为其子项即可。 并且由于您将它们直接/间接添加到此MainWindow作为子项,当您关闭此主窗口时,所有内容都会自动处理。 只需确保您创建的所有动态对象/小部件都是MainWindow的子代/后代即可。 因此不需要显式删除..
QObject
有一个已定义的父级,并且程序的树状结构可以有效地管理内存。
Qt中的动态性会破坏这个好的理想,例如传递一个原始指针。很容易就会持有一个“悬挂指针”,但这是编程中常见的问题。
Qt智能指针实际上是一种弱引用,即QPointer<T>
,并提供了一些STL的便利功能。
也可以与std::unique_ptr
等混合使用,但应仅用于程序中的非Qt机制部分。
main()
中,所以它将被自动收集。 - dtech