QtアプリをVC++ 2008 Expressでデバッグする
メモリリークを出力させてみましょう
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| #if !defined(QT_NO_DEBUG) && defined(WIN32)
#include <crtdbg.h>
#endif
#include "QApplication"
#include "QPushButton"
int main(int argc, char *argv[])
{
#if !defined(QT_NO_DEBUG) && defined(WIN32)
_CrtSetDbgFlag( _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF );
#endif
QApplication app(argc, argv);
QPushButton hello("Hello world");
hello.resize(100, 30);
// メモリリーク
int *pint=new int[10];
hello.show();
return app.exec();
}
|
一般的にWIN32でメモリリークのチェックを行うときと同じように処理を入れてみました。
結果は、以下のように出力されました。
Detected memory leaks!
Dumping objects -->
{1691} normal block at 0x00AD0320, 40 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
|
上々の結果です。
Qtをご存知の方は、Qt3で、上記のソースコードでメモリリークが大量に出力されていたのを思い出されていたのではないでしょうか。
(VC++2008とQt4.5.1の組み合わせでは、上記の結果となりました。)
さて、Qtでは、自動的に自身が管理しているオブジェクトを削除するような仕組みを持っています。
例えば、
QWidget に QPushButton を表示させた場合、
QPushButtonは、newで生成され、そのオブジェクトをQWidgetへ配置します。
後は、QWidgetが自身が破棄されるタイミングで、先のQPushButtonも破棄しますので、ユーザは、deleteをしなくて良いようになっています。
この例をサンプルソースコードを使ってあらわしてみましょう。
- MyWidget.h
-- メイン画面(ヘッダ)で、終了するボタンを一つだけ持ちます。
- MyWidget.cpp
-- メイン画面(ソース)で、終了するボタンを一つだけ持ちます。
- sample.cpp
-- メイン画面を表示して、終了するだけです。
[MyWidget.h]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
| #ifndef _MYWIDGET_H_
#define _MYWIDGET_H_
#include "QApplication"
#include "QPushButton"
#include "QVBoxLayout"
////////////////////////////////////////
// メモリーリーク検証のためのデータクラス
class LocalData
{
public:
LocalData();
int m_ndata;
};
////////////////////////////////////////
// メモリーリーク検証のための画面クラス
class MyWidget : public QWidget
{
public:
MyWidget( QWidget *parent=0 ) ;
QPushButton *m_pquit; // ボタンをnewする
QVBoxLayout *m_playout; // レイアウトをnewする
QPushButton *m_pquit2; // ボタンをnewする
LocalData *m_plocaldata; // ローカルデータをnewする
};
#endif
|
10-15行目は、メモリリーク検証用にQtに依存しないクラスを定義しています。
[MyWidget.cpp]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
| #include "MyWidget.h"
////////////////////////////////////////
// メモリーリーク検証のためのデータクラス
LocalData::LocalData ()
{
m_ndata=99;
}
////////////////////////////////////////
// メモリーリーク検証のための画面クラス
MyWidget::MyWidget( QWidget *parent) : QWidget( parent, 0 )
{
setMinimumSize( 200, 100 );
setMaximumSize( 400, 400 );
// ボタンをnewする
m_pquit = new QPushButton( "Quit", this );
// レイアウトをnewする
m_playout = new QVBoxLayout;
m_playout->addWidget(m_pquit);
setLayout(m_playout);
// 関連のないボタンをnewする
// *****このオブジェクトは、メモリーリークと判断される
m_pquit2 = new QPushButton( "Quit2");
// ローカルデータをnewする
// *****このオブジェクトは、メモリーリークと判断される
m_plocaldata = new LocalData;
Q_ASSERT(m_plocaldata->m_ndata==99);
connect( m_pquit, SIGNAL(clicked()), qApp, SLOT(quit()) );
setWindowTitle(QString ("test dialog"));
}
|
19行目は、実際にこの画面に貼り付ける"Quit"ボタンを作成(new)しています。
28行目は、この画面に貼り付けない"Quit2"ボタンを作成(new)しています。
32行目は、Qtに依存しませんが、この画面のメンバーとして個別のクラスを生成(new)しています。
[sample.cpp]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| #if !defined(QT_NO_DEBUG) && defined(WIN32)
#include <crtdbg.h>
#endif
#include "QApplication"
#include "QPushButton"
#include "MyWidget.h"
int main(int argc, char *argv[])
{
#if !defined(QT_NO_DEBUG) && defined(WIN32)
_CrtSetDbgFlag( _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF );
#endif
QApplication app(argc, argv);
MyWidget hello;
hello.show();
return app.exec();
}
|
16,18行目は、画面を表示しているだけです。
では、これをデバッグ版でコンパイルして、デバッグ実行してみると結果は、大量のメモリリーク情報が出力されます。
[MyWidget.cpp]の26-33行目までをコメントアウトして、同様にデバッグ実行してみると結果は、今度はメモリリークが何も
出力されなくなります。
Qtで、きれい?に関連を持たせてあげると、正しく、メモリリークを出力してくれるようです。
Qtで提供されている2,3個のサンプルで、試してみましたが、一応、メモリリークは出力されませんでした。
少しは、このメモリリークのチェック機能も使えるようになったのではないかなと思います。
Qtのメモリリークについては、随分、以前から問題と言うか、チェックの方法について、侃々諤々(かんかんがくがく)、議論があるようです。
Linux系では、無償のメモリチェックツール"Valgrind"が、よく使われていたようです。
Windowsでは、無償のメモリチェックツールはありません。(もしご存知の方がいらっしゃれば、ご一報ください。)
有償の高価?な"Insure++"などが必要とされていました。
確かに、有償パッケージを利用した方が効果的かもしれませんが、以前に比べると、随分、QtもWindowsの環境に馴染んできたのかな
という印象を持ちました。(上記のやり方で、どこまで、使えるか不明な点も多いですが・・・。)
この記事で、何かお気づきの点がありましたら、コメントいただければ幸いです。
追記:Toobarやメニューでアイコンを使ったサンプルでは、うまくいかないことがあります。まだ、他にもうまくいかないパターンがあるかもしれませんので、
この中途半端なメモリーリークチェックをご利用の場合は、十分、ご注意ください。
Qtでも、MFCとのMixedを行ったとき、エラーが出るとしています。
※前回のサンプルプログラムに不具合がありましたので、修正しておきました。ダウンロードされた方、すみません。

もっと、Qt関連について詳しく知りたい方は、以下の本なども良いと思います。
Qtに関する日本語の本が少ないですね。「入門書」は、さすがに、このページを読まれるくらいの方は不要だと思います。
やっぱり、本+ネット+試してみる!!の3本柱でやっていく以外にないように思います。
コメントをどうぞ