I.はじめに
Qtのメモリ管理:Qtの内部のオブジェクトの階層を維持することができます。視覚的要素のため、この階層は、親コンポーネントサブアセンブリとの関係で、非視覚的要素のため、それは別のオブジェクトへのオブジェクトの所属です。Qtのでは、Qtは、親はその子に沿って削除削除させていただきます。
(一から一)C ++は、削除して、新しいのペアリングする必要があります。以下、メモリリーク、はるかに大きなトラブルを削除します。Qtはめったに新しいで使用しない場合は削除して、QObjectのクラスはクラスを継承しているため、親を設定(にaddChildのsetParent機能はまた、建設または親で使用することができる)ので、親が削除され、親の子はすべて関連しています自動的にマニュアル処理せず、削除してください。しかし、親は子供がそれを区別するために、新規であるか、スタックに割り当てられていません。これは、強力な削除を反映して、任意のオブジェクトを解放することができ、および削除スタックオブジェクトは、Qtの半自動メモリ管理を知っておく必要がありますメモリエラーにつながることができます。もう一つの問題:子供は、彼らはそれを削除しているかどうかわからない、それは野生のポインタを表示されることがあります。彼らは、スマートポインタQPointerのQtを理解しなければなりません。
第二に、詳細な
1は、Qtの半自動メモリ管理
(1)とその派生クラスはQObjectオブジェクトは、その親の非ゼロのオブジェクトは、次いで、デストラクタは、親デストラクタなる場合。
(2)オブジェクトは、その派生クラスは、Qtの:: WA_DeleteOnCloseフラグを設けてもよいQWidgetの(閉じたときにオブジェクトのデストラクタ)。
(3)オブジェクトQAbstractAnimation派生クラスは、QAbstractAnimation :: DeleteWhenStoppedを設けてもよいです。
(4)QRunnable :: setAutoDelete()、MediaSourceの:: setAutoDelete()。
(5)親子関係:親、子オブジェクト、親と子の関係。これは、親に関連する伝送パラメータ(システムのために、親から独立している基底クラス、派生クラス、または親クラス、サブクラスは、導出される)、クラスに固有のQtに継承とは無関係です。
図2に示すように、メモリの問題の例
- 例1
#include <QApplication>
#include <QLabel>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QLabel *label = new QLabel("Hello Qt!");
label->show();
return a.exec();
}
分析: ラベルもない親、もそのコールは、削除することがメモリリークが発生します。本のポインタメモリの問題で、この小さな例が表示されます。改善された方法:スタック上の割り当ての代わりに、ヒープ、次のように:
(1)の代わりに、ヒープのスタックに割り当てました:
#include <QApplication>
#include <QLabel>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QLabel label("Hello Qt!");
label.show();
return a.exec();
}
(2)フラグを設定し、クローズ(後)ラベルを削除します:
label->setAttribute(Qt::WA_DeleteOnClose);
(3)新しい手動で削除した後:
#include <QApplication>
#include <QLabel>
int main(int argc, char *argv[])
{
int ret = 0;
QApplication a(argc, argv);
QLabel *label = new QLabel("Hello Qt!");
label->show();
ret = a.exec();
delete label;
return ret;
}
- 例2
#include <QApplication>
#include <QLabel>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QLabel label("Hello Qt!");
label.show();
label.setAttribute(Qt::WA_DeleteOnClose);
return app.exec();
}
分析:ラベルが近い場合には、削除&ラベルため、プログラムがクラッシュした。しかし、ラベルオブジェクトは、スタックメモリ空間に割り当てられている、間違っていると、スタック上のアドレスを削除します。一部の人々はラベルが誤って二度削除するように理解されている、あなたはQLabelラベル(「こんにちはQtのを!」テストすることができます ); Label.show();削除&ラベル、 最初に発生するエラーを削除します。
- 例3
#include <QApplication>
#include <QLabel>
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
QLabel label("Hello Qt!");
QWidget w;
label.setParent(&w);
w.show();
return app.exec();
}
分析:クラッシュ閉じワット時。オブジェクトが内部リストを持って、子どもたちだけでなく、親、自分自身の破壊を保存するためのポインタを保存します、親リストとデストラクタからすべての子を自分自身を削除します。wがデストラクタである場合、W比ラベルは、最初のデストラクタであるオブジェクトラベルchilrenリストを削除するが、ラベルスタックにスタックを削除することにより、物体上にあり、エラーに割り当てられています。
方法を改善します:
ラベルデストラクタは、親オブジェクトのリスト、及びWデストラクタから自身を削除する(1)スタック内が割り当てられる、親ラベルが破壊されるように確保リスト内の子供をシーケンスを調整オブジェクト。
#include <QApplication>
#include <QLabel>
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
QWidget w;
QLabel label("Hello Qt!");
label.setParent(&w);
w.show();
return app.exec();
}
(2)ヒープに割り当てられたラベルを
QLabel *label = new QLabel("Hello Qt!");
label->setParent(&w)
または:
QLabel *label = new QLabel("Hello Qt!",this);
- 例4
ワイルドポインタ
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
QWidget *w = new QWidget;
QLabel *label = new QLabel("Hello Qt!");
label->setParent(w);
w->show();
delete w;
label->setText("go"); //野指针
return app.exec();
}
分析:プログラムが異常終了した場合、削除、それはラベルがダングリングポインタ(オブジェクトへのラベルポイントが削除されている)になって、wのラベルを削除します(「行く」)ラベル=>のsetTextを呼び出し 、 エラーが発生しました。
改善された方法:QPointerスマートポインタ(QPointerオブジェクトのみを指すために使用することができ、QObjectのクラスを派生)
#include <QApplication>
#include <QLabel>
#include <QPointer>
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
QWidget *w = new QWidget;
QLabel *label = new QLabel("Hello Qt!");
label->setParent(w);
QPointer<QLabel> p = label;
w->show();
delete w;
if (!p.isNull()) {
label->setText("go");
}
return app.exec();
}
- 例5
deleteLater
QObjectのは、イベントキューを受信しているとき、彼女はあなたを破壊するために出ている場合、それが問題であるので、我々はあなたがdeleteLaterはQObject()関数を使用するために、そうしなければならない場合QTは、QObjectをから直接削除構築していない、それは意志すべてのイベントが持つすべての取引が完了した後のメモリをクリーンアップ、さらには問題ありません。何回もdeletelater呼び出すためにすぐに送信されます。
イベントシステムに削除イベントを送信します。
void QObject::deleteLater()
{
QCoreApplication::postEvent(this, new QEvent(QEvent::DeferredDelete));
}
第三に、メモリリーク検出ツール-VLD
ビジュアル漏れ検出器(VLD)は、ビジュアルC ++のためのメモリリーク検出ツールの無料です。あなたはメモリリークレポートのレベルを設定することができます;あなたは完全なデータ漏洩メモリを得ることができ、あなたが、あなたはまた、ファイルと行番号でそれを得ることができた場合は、コールスタックのメモリリークポイントを取得することができますし、無料で開いている:彼の特徴です。しかし、唯一のMingGWコンパイラをサポートしていないMSVCコンパイラをサポートします。
ダウンロードします。http://vld.codeplex.com/
インストールが完了したら、2つのヘッダは、次のデフォルトへのQtのインストールディレクトリを含め、インストールディレクトリのlib VLD下のlibディレクトリに対応する、ディレクトリを含めるVLDをコピーしますデフォルトのQtのlibディレクトリにファイルをコピーします。そして、main.cppを中
#include<vld.h>
使用する準備ができました。
QTスマートポインタ
(1)QPointer
QPointerはテンプレートクラスです。その以外、QPointerオブジェクトが動的にスペースを割り当てることができる監視、および場合削除オブジェクトを更新、通常のポインタと同様です。
QPointerの現実原則:自分のデストラクタを通じて(デストラクタ、QWidgetのを破壊したときにQPointerでグローバル変数を管理するための指針(ダブルポインタ)にQObjectのポインタとポインタを保存し、QObjectを、むしろQPointerポインタがコースをゼロにするような問題は、2-ポインタであるので、*はゼロに設定されているグローバルGuardHashダブルポインタにQObjectPrivate :: clearGuards関数を呼び出します)はQObjectに頼るより。その上には、IsNull判断が空であると。
// QPointer 表现类似普通指针
QDate *mydate = new QDate(QDate::currentDate());
QPointer mypointer = mydata;
mydate->year(); // -> 2005
mypointer->year(); // -> 2005
// 当对象 delete 之后,QPointer 会有不同的表现
delete mydate;
if(mydate == NULL)
printf("clean pointer");
else
printf("dangling pointer");
// 输出 dangling pointer
if(mypointer.isNull())
printf("clean pointer");
else
printf("dangling pointer");
// 输出 clean pointer
(2)自動ガベージコレクション機構QObjectCleanupHandler:
Qtはクリーナーオブジェクトは自動ガベージコレクションを達成するために非常に重要な部分です。QObjectCleanupHandlerは、サブオブジェクトの多くを登録し、自動的に削除するために自分の時間ですべての子オブジェクトを削除することができます。子オブジェクトのリストから削除するように同時に、子オブジェクトが削除されているかどうかを認識することができます。このクラスは、洗浄操作で使用することができるこのクラスの使用は非常になり、その場合には、同じクラス階層、別のウィンドウに親属性ウィンドウボタンが不可能であるため、例えば、ボタンは多くのウィンドウを閉じるために押されたときに、必要、ではありません便利。
#include <QApplication>
#include <QObjectCleanupHandler>
#include <QPushButton>
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
// 创建实例
QObjectCleanupHandler *cleaner = new QObjectCleanupHandler;
// 创建窗口
QPushButton *w = new QPushButton("Remove Me");
w->show();
// 注册第一个按钮
cleaner->add(w);
// 如果第一个按钮点击之后,删除自身
QObject::connect(w, SIGNAL(clicked()), w, SLOT(deleteLater()));
// 创建第二个按钮,
注意,这个按钮没有任何动作
w = new QPushButton("Nothing");
cleaner->add(w);
w->show();
// 创建第三个按钮,删除所有
w = new QPushButton("Remove All");
cleaner->add(w);
QObject::connect(w, SIGNAL(clicked()), cleaner, SLOT(deleteLater()));
w->show();
return app.exec();
}
//在上面的代码中,创建了三个仅有一个按钮的窗口。第一个按钮点击后,会删除掉自己(通过 deleteLater() 槽),此时,cleaner 会自动将其从自己的列表中清除。第三个按钮点击后会删除 cleaner,这样做会同时删除掉所有未关闭的窗口。