Qtでのメモリ管理?


96

私はQtにかなり慣れていないので、メモリ管理やオブジェクトの寿命に関する基本的なことについて疑問に思っています。オブジェクトをいつ削除または破棄する必要がありますか?これは自動的に処理されますか?

次の例では、作成するオブジェクトのうち、削除する必要があるのはどれですか。が破棄さmyOtherClassれるmyClassと、インスタンス変数はどうなりますか?オブジェクトをまったく削除(または破棄)しないとどうなりますか?それは記憶の問題でしょうか?

MyClass.h

class MyClass
{

public:
    MyClass();
    ~MyClass();
    MyOtherClass *myOtherClass;
};

MyClass.cpp

MyClass::MyClass() {
    myOtherClass = new MyOtherClass();

    MyOtherClass myOtherClass2;

    QString myString = "Hello";
}

ご覧のとおり、これは初心者にとっては簡単なことですが、簡単な方法でこれについてどこで学ぶことができますか?

回答:


100

QObjects を使用して独自の階層を構築する場合、つまり、新しく作成されたすべてQObjectのを親で初期化します。

QObject* parent = new QObject();
QObject* child = new QObject(parent);

それは十分にあるので、Sのデストラクタは、破壊の世話をします。(これはシグナルを発行することによって行われるため、親の前で手動で削除した場合でも安全です。)deleteparentparentchildchild

最初に子を削除することもできます。順序は関係ありません。順序重要な例として、オブジェクトツリーに関するドキュメントを次に示します

MyClassがの子でない場合はQObject、単純なC ++の方法を使用する必要があります。

また、QObjectsの親子階層は通常、C ++クラス階層/継承ツリーの階層から独立していることに注意してください。つまり、割り当てられた子は、その親の直接のサブクラスである必要はありません。任意の(のサブクラス)でQObject十分です。

ただし、他の理由でコンストラクターによって課されるいくつかの制約がある可能性があります。などのQWidget(QWidget* parent=0)場合、親は別のQWidgetである必要があります。たとえば、可視性フラグや、基本的なレイアウトをそのように行うためです。しかし、Qtの一般的な階層システムでは、任意のユーザーをQObject親として持つことができます。


21
(It does this by issuing signals, so it is safe even when you delete child manually before the parent.)->これが安全な理由ではありません。Qt 4.7.4では、QObjectの子が直接削除されます(deleteqobject.cpp、1955行を参照)。最初に子オブジェクトを削除しても安全である理由は、QObjectが削除されたときにQObjectがそれを忘れるように親に通知するためです。
マーティンヘニングス

5
これが真実であるためには、子孫のデストラクタが仮想であることを確認する必要があることを付け加えます。場合ClassBから継承QObjectし、ClassC継承からClassB、そのClassC場合にのみ、適切にQtの親子関係によって破壊されてしまいますClassBのデストラクタが仮想です。
フルーシャ

1
答えのリンクは今壊れています(ほぼ4年後に驚くことではありません...)、おそらくこれはこのようなqt-project.org/doc/qt-4.8/objecttrees.htmlのようなものでしたか?
PeterSW、2014

2
@Phlucious QObjectのデストラクタはすでに仮想化されているため、すべてのサブクラスのデストラクタが自動的に仮想化されます。
rubenvb 2016

1
継承ツリーのどこかにあるクラスに仮想デストラクタがある場合、以下のすべての子クラスには仮想デストラクタがあります。さて、仮想デストラクタのない仮想デストラクタチェーンの外側にリーフ親クラスがある場合、実際のオブジェクトがそのチェーンのどこかにあるときにその特定のクラスへのポインタを削除すると問題が発生する可能性があると思います。QObjectの子クラスで、その子クラスのインスタンスへのQObjectポインターを削除する場合、そのサブクラスのデストラクタ宣言で仮想キーワードを忘れても問題はありません。
rubenvb 2016

47

Qtでは所有権の概念が非常に重要であることを指摘して、Debilskiの回答を拡張したいと思います。クラスAがクラスBの所有権を引き継ぐ場合、クラスAが削除されるとクラスBも削除されます。オブジェクトを作成してその親を指定するときだけでなく、あるオブジェクトが別のオブジェクトの所有者になる状況がいくつかあります。

例えば:

QVBoxLayout* layout = new QVBoxLayout;
QPushButton someButton = new QPushButton; // No owner specified.
layout->addWidget(someButton); // someButton still has no owner.
QWidget* widget = new QWidget;
widget->setLayout(layout); // someButton is "re-parented".
                           // widget now owns someButton.

もう一つの例:

QMainWindow* window = new QMainWindow;
QWidget* widget = new QWidget; //widget has no owner
window->setCentralWidget(widget); //widget is now owned by window.

したがって、ドキュメントを頻繁に確認してください。通常、メソッドがオブジェクトの所有権に影響を与えるかどうかが指定されています。

Debilskiが述べたように、これらのルールはQObjectから派生したオブジェクトにのみ適用されます。クラスがQObjectから派生していない場合は、破棄を自分で処理する必要があります。


書き込みの違いは何ですか?QPushButton * someButton = new QPushButton(); またはQPushButton someButton =新しいQPushButtonまたは単にQPushButton someButton;
マーティン

3
ええと、QPushButtonには大きな違いがあります* someButton = new QPushButton; およびQPushButton someButton;。前者はヒープにオブジェクトを割り当て、後者はスタックに割り当てます。QPushButton * someButton = new QPushButton();の間に違いはありません。およびQPushButton someButton = new QPushButton ;、どちらもオブジェクトのデフォルトコンストラクターを呼び出します。
オースティン

私はこれを非常に新しいので、申し訳ありませんが、「ヒープにオブジェクトを割り当てる」と「スタックに割り当てる」の違いは何ですか?いつヒープを使用し、いつスタックを使用する必要がありますか?ありがとう!
マーティン

3
動的割り当て、オブジェクトスコープ、RAIIについて読む必要があります。プレーンなC ++の場合、オブジェクトはスコープを使い果たすと自動的に破棄されるため、可能な限りスタックにオブジェクトを割り当てる必要があります。クラスメンバーの場合、パフォーマンス上、オブジェクトをヒープに割り当てる方が適切です。また、オブジェクトが関数/メソッドの実行よりも長く存続するようにしたい場合は常に、オブジェクトをヒープに割り当てる必要があります。繰り返しますが、これらは非常に重要なトピックであり、いくつかの資料を読む必要があります。
オースティン

@Austinパフォーマンスのためにヒープにクラスメンバーを割り当てる必要があるという一般的なステートメントは、ブロックです。それは本当に依存し、パフォーマンスの問題が見つかるまで、自動保存期間を持つ変数を優先する必要があります。
rubenvb 2016

7

親(QObjectオブジェクトまたはその派生クラス)には、その子(QObject /その派生)へのポインタのリストがあります。親は破棄されますが、親は子リスト内のすべてのオブジェクトを削除します。QObjectのこのプロパティを使用して、親が削除されたときに子オブジェクトを自動的に削除することができます。関係は次のコードを使用して確立できます

QObject* parent = new QObject();
QObject* child = new QObject(parent);
delete parent;//all the child objects will get deleted when parent is deleted, child object which are deleted before the parent object is removed from the parent's child list so those destructor will not get called once again.

smartpointerを使用して、Qtでメモリを管理する他の方法があります。次の記事では、Qtのさまざまなスマートポインターについて説明します。 https://blog.qt.digia.com/blog/2009/08/25/count-with-me-how-many-smart-pointer-classes-does-qt-have/


-2

これらの回答に加えて、検証のVisual Leak Detetorために、c ++に基づいているため、Qtプロジェクトを含むVisual c ++プロジェクトのライブラリを利用することをお勧めします。このライブラリはnew, delete, free and mallocステートメントと互換性があり、十分に文書化されており、使いやすいです。独自QDialogまたはQWidget継承されたインターフェイスクラスを作成し、このクラスの新しいオブジェクトを作成するsetAttribute(Qt::WA_DeleteOnClose)場合は、オブジェクトの関数を実行することを忘れないでください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.