为什么有关Qt库的官方示例和教程从不使用智能指针?我只看到new
和delete
用于创建和销毁小部件。
我搜索了基本原理,但找不到它,除非是出于历史原因或向后兼容,否则我自己也看不到:不是每个人都希望程序在小部件构造函数失败时终止,并通过try / catch处理它块是丑陋的(即使在很少的地方使用)。父母小部件可能拥有孩子的所有权这一事实也仅向我部分解释了这一点,因为您仍必须delete
在某种程度上为父母使用。
为什么有关Qt库的官方示例和教程从不使用智能指针?我只看到new
和delete
用于创建和销毁小部件。
我搜索了基本原理,但找不到它,除非是出于历史原因或向后兼容,否则我自己也看不到:不是每个人都希望程序在小部件构造函数失败时终止,并通过try / catch处理它块是丑陋的(即使在很少的地方使用)。父母小部件可能拥有孩子的所有权这一事实也仅向我部分解释了这一点,因为您仍必须delete
在某种程度上为父母使用。
main()
因此它将被自动收集。
Answers:
因为Qt依赖于父子模型来管理Qobject资源。它遵循复合+责任链模式,从事件管理到内存管理,绘图,文件处理等使用...
实际上,尝试在共享\唯一指针中使用QObject是过度设计的(99%的时间)。
deleteLater
直接致电。也就是说,您仍然可以将RAII与Qt一起使用。例如,QPointer充当上的弱引用QObject
。我会使用QPointer<QWidget>
而不是QWidget*
。
注意:不要听起来太狂热,两个词:Qt + valgrind。
deleteLater
而不是简单地delete
将其对象化?我经常使用智能指针来管理QObject派生类的实例,因此我一直在寻找答案,以确保我没有做任何危险的事情,并且据我所知文档未表明它是错到delete
一个QObject指针正常(即使它是由父对象拥有的,因为析构函数将删除父参考)。
QObject
从另一个中删除一个QThread
。的析构函数QObject
断开与之的所有信号连接,并自动从其事件队列中删除未决事件。因此,调用delete
上QObject
是好的,如果你从它的线程内做到这一点。话虽如此,deleteLater()
除非您出于某种原因需要立即清理,否则您几乎不会做任何错误的事情。
智能指针类std::unique_ptr
和std::shared_ptr
用于内存管理。拥有这样的智能指针意味着您拥有该指针。但是,在QObject
与QObject
父级一起创建或派生类型时,所有权(清理的责任)将移交给父级QObject
。在那种情况下,标准库智能指针是不必要的,甚至是危险的,因为它们可能导致双重删除。kes!
但是,在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 ++建议:不要对其他程序实体拥有的对象使用智能指针。
您已经回答了自己的问题:except if it's for historic reasons/backward compatibility
。像QT一样庞大的库不能假设使用该库的每个人都有支持C ++ 11的编译器。new
并delete
保证存在于较早的标准中。
但是,如果您确实支持使用智能指针,那么我建议您将其用于原始指针。
auto_ptr
,那么不使用它是正确的决定。C ++ 11之前没有好的标准化智能指针。
QSharedPointer
和QScopedPointer
。
除了@Jamey所说的:
如果您设计巧妙,则可能永远不必在小部件上使用删除功能。假设您有一个主窗口,并且正在为其创建一个自动对象,并在事件循环中运行该窗口。现在,该小部件中的其余所有项目都可以作为其子级添加。并且由于您是直接/间接将它们作为子级添加到此MainWindow中,因此当您关闭此主窗口时,所有内容都会自动处理。只需确保您创建的所有动态对象/小部件都是MainWindow的子代/孙代即可。因此,无需显式删除。