【ACCESS精品源码栏目提醒】:文章导读:在新的一年中,各位网友都进入紧张的学习或是工作阶段。
网学会员整理了ACCESS精品源码-Qt_动态内存管理 - 软件工程的相关内容供大家参考,祝大家在新的一年里工作和学习顺利!
Qt 的动态内存回收问题(1) Qt 的动态内存回收机制容易让人觉得困惑,而能够参考的相关资料又很少,不少都是对此一笔带过,或者给出错误的说明。
费了不少劲,了解到了一些皮毛。
email:wulinshuxuehotmail.com1、一篇博文http://www.cppblog.com/biao/archive/2009/07/02/89079.html在这篇博文中,提到了 Qt 的窗口回收机制,复制了过来。
大家也可以去原网址看。
Qt: 释放窗口资源1. 对于使用指针,使用 new 创建的窗口,当然可以使用 delete 显示的释放其占用的资源:Widget w new Widgetdelete w2. 对于使用指针,使用 new 创建的窗口,还可以使用QWidget::setAttribute 方法来当窗口关闭后自动释放其占用的资源,而不用户显示的去调用 delete 释放,此方法当然也会调用窗口的析构函数:Widget w new Widgetw-gtsetAttributeQt::WA_DeleteOnClose (在程序中测试过一次,该值默认值为 false,需要通过 setAttribute 来置为 true)这可以用于非模态对话框,因为非模态对话框如果是用指针形式创建,但是再接着 delete 的话,窗口就没了,如果不使用 delete 释放窗口占用的资源,又会赞成泄漏。
如果使用普通变量创建,同样的也因为变量作用域马上就结束而窗口也没了,另一种方法就是使用多线程,不过这个的代价大了点。
所以这种技术在创建非模态对话框上是非常典型的运用。
测试方式:在 Widget 中分配大量的内存,显示与关闭多个此类窗口,看看任务管理器里此程序的内存变化情况, 是否真正的释放了占用的内存(当然释放了)。
在 C中使用 new 分配内存时,如 array new doublelength,此时,给 array 的内存实际上并没有真正的分配,必须等到第一次使用这些内存后才会真正地为其分配物理内存,如:memsetarray 1 length sizeofdouble又一篇博文:/http://topic.csdn.net/u/20101115/19/839436ff‐8e51‐4e89‐bd75‐ab452fb2a494.html发表于:2010-11-15 19:32:20class MainWindow构造函数中增加:setAttributeQt::WA_DeleteOnClose以后,C/C code MainWindow mainWindow mainWindow.setGeometry30301024768 mainWindow.show当关闭 mainWindow 时候,会有异常。
改成:C/C code MainWindow mainWindow new MainWindow mainWindow-gtsetGeometry30 30 1024 768 mainWindow-gtshow这样才可以,原因就是前者定义在栈上,后者定义在堆上,所以当设置了 WA_DeleteOnClose 以后,调用 MainWindow 析构函数才不会异常抛出。
setAttributeQt::WA_DeleteOnClose 什么原理,有没有人研究过
源码?/3. 窗口的内存管理交给父 Widget:Widget w new Widgetparent但这时,如果父 Widget 不结束,这个窗口的资源一直会占用着。
至于使用哪种技术来释放窗口的资源,要看具体的运用时,哪种方式更合适。
2、一本书看到了《Foundations of Qt Development》,作者是 Johan Thelin。
这本书很适合使用过 C,开始接触 Qt 的程序员阅读。
下面的内容摘自该书,有点涉嫌侵权。
Making C “Qt-er”Because this is a book on programming you will start with some coderight away see Listing 1-1.让 CQt 化Listing 1-1. A simple C class 一个简单的 C类include ltstringgtusing std::stringclass MyClasspublic:MyClass const stringamp text const stringamp text constvoid setText const stringamp text int getLengthOfText constprivate:string m_textLet’s make this class more powerful by using Qt.Inheriting QtThe first Qt-specific adjustment you will make to the code is reallysimple: you will simply letyour class inherit the QObject class which will make it easier tomanage instances of the classdynamically by giving instances parents that are responsible for theirdeletion.第一个 Qt 化的调整相当简单,让你的类继承 QObject 类就行了。
这会使得对类的实例的动态管理更加简单。
因为可以通过给实例父对象,这样就由父对象来负责删除了。
it is common—and recommended—to pass the parent asan argument to the constructor as the first default argument to avoidhaving to type setParentfor each instance created from the class.一个惯例,并且也是推荐的方式是,将父对象作为一个参数传给构造函数,成为第一个缺省参数。
Listing 1-2. Inheriting QObject and accepting a parent继承 QObject 并接受父对象include ltQObjectgtinclude ltstringgtusing std::stringclass MyClass : public QObjectpublic:MyClass const stringamp text QObject parent 0 ...Let’s look at the effects of the change starting with Listing 1-3.Itshows a main functionusing the MyClass class dynamically without Qt.下面我们看看变化。
首先是不用 Qt:Listing 1-3. Dynamic memory without Qt不用 Qt 使用动态内存include ltiostreamgtint main int argc char argv MyClass a b ca new MyClass quotfooquot b new MyClass quotba-a-arquot c new MyClass quotbazquot std::cout ltlt a-gttext ltlt quot quot ltlt a-gtgetLengthOfText ltlt quotquot ltltstd::endla-gtsetText b-gttext std::cout ltlt a-gttext ltlt quot quot ltlt a-gtgetLengthOfText ltlt quotquot ltltstd::endlint result a-gtgetLengthOfText - c-gtgetLengthOfTextdelete adelete bdelete creturn resultEach new call must be followed by a call to delete to avoid a memoryleak. Although it isnot a big issue when exiting from the main function because mostmodern operating systemsfree the memory when the application exits the destructors are notcalled as expected. Inlocations other than loop-less main functions a leak eventually leadsto a system crash whenthe system runs out of free memory. Compare it with Listing 1-4which uses a parent that isautomatically deleted when the main function exits. The parent isresponsible for callingdelete for all children and—ta-da—the memory is freed.每个 new 都必须伴随一个 delete 来防止内存泄露。
我们将这个例子和下一个比较。
下面的 1-4 中,使用了一个父对象。
当 main 函数结束时, 父对象会被自动删除。
而这个父对象负责删除所有的孩子。
哒-哒!内存被释放了。
■Note In the code shown in Listing 1-4 the parent object is added toshow the concept. In real life itwould be an object performing some sort of task—for example aQApplication object or in the case ofa dialog box or a window the this pointer of the window class.注意,在下面的代码中,父对象是用来展示概念的。
在实际应用中,它会是一个运行某种任务的对象,比如,QApplication 对象,或者 window 类的 this 指针。
Listing 1-4. Dynamic memory with Qt使用 Qt 的动态内存使用include ltQtDebuggtint main int argc char argv QObject parentMyClass a b ca new MyClass quotfooquot ampparent b new MyClass quotba-a-arquot ampparent c new MyClass quotbazquot ampparent qDebug ltlt QString::fromStdStringa-gttextltlt quot quot ltlt a-gtgetLengthOfText ltlt quotquota-gtsetText b-gttext qDebug ltlt QString::fromStdStringa-gttextltlt quot quot ltlt a-gtgetLengthOfText ltlt quotquotreturn a-gtgetLengthOfText - c-gtgetLengthOfTextIt might look odd to have a parent object like this but most Qtapplications use a QApplication object to actas a parent.有这样一个父对象也许看起来有点怪怪的。
但是,大多 Qt 应用程序使用一个QApplication 对象来作为父对象。
When comparing the code complexity in Listing 1-3 and Listing 1-4look at the differentmemory situations as shown in Figure 1-1. The parent is graybecause it is allocated on thestack and thus automatically deleted whereas the instances ofMyClass are white because theyare on the heap and must be handled manually. Because you use theparent to keep track ofthe children you trust the parent to delete them when it is beingdeleted. So you no longerhave to keep track of the dynamically allocated memory as long as theroot object is on thestack or if you keep track of it.由于父对象在栈空间里,所以就不用你来负责空间释放,这样,它的子对象占用的动态内存也就无需去手动释放了。
Qt 的动态内存回收问题(2)3、一篇博文http://my.oschina.net/janpoem/blog/7186转纠正你的 Qt 编程习惯:主窗体的创建问题发表于 2010 年 09 月 02 日 19:49 分类: Qt 统计: 0 评/482 阅 3 人收藏此文章, 收藏此文章关键字: Qt原文纠正你的 Qt 编程习惯:主窗体的创建问题题记: 要知道,并不是只有初学者才会犯错。
(shiroki 的至理名言)最近发现了一些有意思的问题,值得 memo 一下。
先来看段代码:
源码打印? 1. includeltQApplicationgt 2. includeltQWebViewgt 3. includeltQUrlgt 4. intmainintargccharargv 5. 6. QApplicationaargcargv 7. QWebViewmwnewQWebView 8. mw‐gtshow 9. mw‐gtloadQUrlquothttp://www.cuteqt.com/blogquot 10. returna.exec 11. 大家看得出这段代码中的问题吗? (呵呵,不要告诉我是 cuteqt 不能访问哦)这段代码 ms 十分标准, 非常符合笔者平时写 Qt 程序书写 main 函数的习惯, 孰料想竟然是个错误的习惯,而且问题很严重哦。
给个提示:在程序退出时会 aborted。
如果还没想出来是什么问题,嘿嘿,没关系,看了下面的答案你就明白了。
在这段程序里 QApplication 实例创建在 stack 上,生命期是 main 的大括号内, 而 mw则通过 new 创建在 heap 上, 在程序退出时才会被析构。
换句话说,mw 的生存期长于application 的生存期…..这可是 Qt 编程的大忌, 因为在 Qt 中所有的 Paint Device 都必须要在有 QApplication 实例的情况下创建和使用。
不过如果把这个程序写出来运行一下,未必会出现我说的 aborted 的问题, 大多数代码类似的程序都能安全的运行(这也是为什么用了那么多年的 Qt 从来没有注意过这个问题, 并且养成了我错误的编程习惯。
。
这 )里的 trick 在于 application 退出时 mw 已经被关闭, mw 中的所有 Paint Device 一般都不会被访问到了, 所以这个错误隐藏在很深的阴暗角落, 偷偷地嘲笑我们呢!要想试验这个问题也很简单,把 load 的参数换成本地文件 test.html 并把下面的内容写进 test.html 就能看到拉:
源码打印? 1. ltformgt 2. ltselectidquotheadertestquotgt 3. ltoptiongtItem1lt/optiongt 4. ltoptiongtItem2lt/optiongt 5. ltoptiongtItem3lt/optiongt 6. lt/selectgt 7. lt/formgt这个 html 里使用了下拉选单。
如果你运行程序并点开该选单,之后退出程序你就会看到Aborted 错误提示,并打印出错误信息:“QWidget: Must construct a QApplicationbefore a QPaintDevice”。
Qt 的动态内存回收问题(3)既然提出的问题,当然也要给出解决的方案。
有两种可行的方法避免该错误。
一个当然是纠正一下编程习惯,对 mw 不要用 new 的方式创建,改在 stack 上创建,如下代码:
源码打印? 1. includeltQApplicationgt 2. includeltQWebViewgt 3. includeltQUrlgt 4. intmainintargcharargv 5. 6. QApplicationaargcargv 7. QWebViewmw 8. mw.show 9. mw.loadQUrlquothttp://www.cuteqt.com/blogquot 10. returna.exec 11. 另外还可以用 Qt 提供的 API 解决此问题, 想办法让 mw 在 application 之前 clean up, 那就是用 WA_DeleteOnClose 属性。
该属性标示窗体会在 close 时被析构, 这样就保证不会留存在 application 析构之后了, 是个很好的办法。
代码如下:
源码打印? 1. includeltQApplicationgt 2. includeltQWebViewgt 3. includeltQUrlgt 4. intmainintargcharargv 5. 6. QApplicationaargcargv 7. QWebViewmwnewQWebView 8. mw‐gtshow 9. mw‐gtsetAttributeQt::WA_DeleteOnClose 10. //mw‐gtsetAttributeQt::WA_QuitOnClose 11. mw‐gtloadQUrlquothttp://www.cuteqt.com/blogquot 12. returna.exec 13. 发现问题和解决问题是件很有乐趣的事情,大家不要把时间都浪费在猜测上,要多动手多思考才能进步!////Qt Jambi 也存在类似的问题,如果以程序启动的代码块去启动 QApplication,在程序运行过程中,一些资源回收会报出 Null 指针错误,这些错误,通过 debug,最终都会指向 QWidget这个类。
当把 QApplication 启动的执行程序移出 main 函数,问题迎刃而解。
要多注意细节。
Qt 的动态内存回收问题(4)4、几个函数(1)void QApplication::setMainWidget QWidget mainWidget staticSets the applications main widget to mainWidget.In most respects the main widget is like any other widget except thatif it is closed the application exits. QApplication does not takeownership of the mainWidget so if you create your main widget onthe heap you must delete it yourself.You need not have a main widgetconnecting lastWindowClosed to quit is an alternative.On X11 this function also resizes and moves the main widgetaccording to the -geometrycommand-line option so you should setthe default geometry using QWidget::setGeometry before callingsetMainWidget.See also mainWidget exec and quit.(2)int QApplication::exec staticEnters the main event loop and waits until exit is called thenreturns the value that was set toexit which is 0 if exit is calledvia quit.It is necessary to call this function to start event handling. The mainevent loop receives events from the window system and dispatchesthese to the application widgets.Generally no user interaction can take place before calling exec. Asa special case modal widgets like QMessageBox can be used beforecalling exec because modal widgets call exec to start a local eventloop.To make your application perform idle processing i.e. executing aspecial function whenever there are no pending events usea QTimer with 0 timeout. More advanced idle processing schemes canbe achieved using processEvents.We recommend that you connect clean-up code tothe aboutToQuit signal instead of putting it in yourapplications main function. This is because on some platforms theQApplication::exec call may not return. For example on theWindows platform when the user logs off the system terminates theprocess after Qt closes all top-level windows. Hence there is noguarantee that the application will have time to exit its event loop andexecute code at the end of the main function after theQApplication::exec call.See also quitOnLastWindowClosed quit exit processEventsand QCoreApplication::exec.(3)quitOnLastWindowClosed : boolThis property holds whether the application implicitly quits when thelast window is closed.The default is true.If this property is true the applications quits when the lastvisible primary window i.e. window with no parent withthe Qt::WA_QuitOnClose attribute set is closed. By default thisattribute is set for all widgets except for sub-windows. Referto Qt::WindowType for a detailed list of Qt::Window objects.
Access functions: bool quitOnLastWindowClosed void setQuitOnLastWindowClosed bool quit See also quit and QWidget::close.(4)void QObject::deleteLater slotSchedules this object for deletion.The object will be deleted when control returns to the event loop. Ifthe event loop is not running when this function is called e.g.deleteLater is called on an object before QCoreApplication::execthe object will be deleted once the event loop is started.Note that entering and leaving a new event loop e.g. by opening amodal dialog will not perform the deferred deletion for the object tobe deleted the control must return to the event loop from whichdeleteLater was called.Note: It is safe to call this function more than once when the firstdeferred deletion event is delivered any pending events for the objectare removed from the event queue.See also destroyed and QPointer.(5)void QCoreApplication::aboutToQuit signalThis signal is emitted when the application is about to quit the main event loop e.g.when the event loop level drops to zero. This may happen either after a call to quitfrom inside the application or when the users shuts down the entire desktop session.The signal is particularly useful if your application has to do some last-secondcleanup. Note that no user interaction is possible in this state.See also quit.(6)void QWidget::closeEvent QCloseEvent event virtual protectedThis event handler is called with the giveneventwhen Qt receives awindow close request for a top-level widget from the window system.By default the event is accepted and the widget is closed. You canreimplement this function to change the way the widget responds towindow close requests. For example you can prevent the windowfrom closing by callingignoreon all events.Main window applications typically use reimplementations of thisfunction to check whether the users work has been saved and ask forpermission before closing. For example theApplicationExampleuses ahelper function to determine whether or not to close the window: void MainWindow::closeEventQCloseEvent event if maybeSave writeSettings event-gtaccept else event-gtignore See alsoeventhidecloseQCloseEvent andApplicationExample.(7)QObject::QObject virtualDestroys the object deleting all its child objects.All signals to and from the object are automatically disconnected andany pending posted events for the object are removed from the eventqueue. However it is often safer to usedeleteLater rather thandeleting a QObject subclass directly.Warning: All chil.