3

QLayoutオブジェクトがそのウィジェットの所有権を前提としていることを Qt のドキュメントから知っています。しかし、オブジェクトに関する限り、スタック上にオブジェクトを作成し、関数QLayoutを使用してウィジェットに渡すことは安全ですか? setLayoutそれとも、ヒープ上に作成する必要がありますか?

#include <iostream>

#include <QtGui/QApplication>
#include <QPushButton>
#include <QVBoxLayout>

class LoudPushButton : public QPushButton
{
public:
    virtual ~LoudPushButton(){std::cout << "~LoudPushButton()" << std::endl;}
};

class LoudQVBoxLayout : public QVBoxLayout
{
public:
    virtual ~LoudQVBoxLayout(){std::cout << "~LoudQVBoxLayout()" << std::endl;}
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QWidget window;

    // On the heap
    LoudQVBoxLayout* mainlayout = new LoudQVBoxLayout;
    mainlayout->addWidget(new LoudPushButton);
    mainlayout->addWidget(new LoudPushButton);
    window.setLayout(mainlayout);
  /*
    // On the stack
    LoudQVBoxLayout mainlayout;
    mainlayout.addWidget(new LoudPushButton);   
    mainlayout.addWidget(new LoudPushButton);
    window.setLayout(&mainlayout);
  */
    window.show(); 

    return a.exec();
}

// スタック上と // ヒープ上の両方の選択肢は、出口で同じ結果を生成します。

~LoudQVBoxLayout()
~LoudPushButton()
~LoudPushButton()

しかし、これが未定義の動作ではないことを確信できますか? そのレイアウトをwindow呼び出しますか?delete

編集:

Cat Plus Plus による回答を考慮して、次のように推測します。

LoudPushButton button;
mainlayout->addWidget(&button);
mainlayout->addWidget(new LoudPushButton);

button*mainlayoutが同時に削除されることが保証されている場合でも、未定義の動作が発生します。これは本当ですか?

4

2 に答える 2

4

EveryQObjectはその子を削除します。親を持たないオブジェクトのみが自動ストレージを持つことができます。レイアウトQWidget::setLayoutの親を変更します。だから、いいえ、あなたはそれを行うことはできませんQLayout.

于 2012-05-01T14:49:33.170 に答える
1

Qtでは、オブジェクトツリーはQWidgetsをスタック上に構築できるように設計されています。親が子の前に作成されている限り、それらは適切に破壊されます。どちらの例も未定義の動作ではありません。

Qtのドキュメントには例が示され、スタック上の親を使用してウィジェットを作成することが正当である理由が説明されています。

int main()
{
    QWidget window;
    QPushButton quit("Quit", &window);
    ...
}

このコードは正しいです。C++言語標準(ISO / IEC 14882:2003)では、ローカルオブジェクトのデストラクタがコンストラクタの逆の順序で呼び出されると指定されているため、quitのデストラクタは2回呼び出されません。したがって、子のデストラクタquitが最初に呼び出され、windowのデストラクタが呼び出される前に、その親であるwindowから自身を削除します。

レイアウトもいつでも破棄されるように設計されているため、適切に動作する必要があります。QWidget::setLayout ドキュメントには次のように記載されています。

このウィジェットにすでにレイアウトマネージャーがインストールされている場合、QWidgetでは別のレイアウトマネージャーをインストールできません。新しいレイアウトでsetLayout()を呼び出す前に、まず既存のレイアウトマネージャー(layout()によって返される)を削除する必要があります。

Qtレイアウトシステムは、QWidgetsに設定されているQLayoutオブジェクトの存続期間を追跡し、このドキュメントで示されているように、破棄を適切に処理します。QLayoutのデストラクタには、設定されているQWidgetから登録を解除するコードが含まれています。

于 2012-05-01T18:42:17.707 に答える