2017-05-29 10 views
4

「現代のC++」Qtアプリケーションは、できるだけ多くのRAIIを使用しています。ときに、このような可能自動割り当てを使用しても安全であればそこで私は自分自身に尋ねる:Qtに所有権の有無がありますか

#include <QApplication> 
#include <QtWidgets> 
int main(int argc, char **argv) { 
    QApplication app{argc, argv}; 
    QWidget window{}; 
    window.setWindowTitle("Der eine Knopf"); 
    QPushButton button{"Ende"}; 
    QObject::connect(&button, SIGNAL(clicked()), &app, SLOT(quit())); 
    QVBoxLayout layout{}; 
    layout.addWidget(&button); 
    window.setLayout(&layout); 
    window.show(); 
    return app.exec(); 
} 

元チュートリアルコードのに対しポインタとヒープの多くを持っていた:

#include <QApplication> 
#include <QtWidgets> 

int main(int argc, char **argv) { 
    QApplication app{argc, argv}; 
    QWidget window{}; 
    window.setWindowTitle("Hallo Qt"); 
    QPushButton button = new QPushButton("Ende"); 
    QObject::connect(button, SIGNAL(clicked()), 
     &app, SLOT(quit())); 
    QVBoxLayout *layout = new QVBoxLayout; 
    layout->addWidget(button); 
    window.setLayout(layout); 
    window.show(); 
    return app.exec(); 
} 

私はQtの所有権を認識してい一般的にQObjectの概念。だから私は2番目の例が正しいと仮定します。私はsetLayoutaddWidgetも所有権を変更すると仮定しているので、明示的なdeleteはクライアントとして私に必要です。

私が疑問に思うと仮定すると、なぜ私の最初の例はそれで動作しますか?これらのメソッドが所有権を取得する場合、最後に新たに取得した子どもはdeleteになりませんか?もしそうなら、オブジェクトが2回削除されるので私のプログラムはクラッシュしませんか?しかし、それは偶然ではありますか?)

誰が誰を所有しているのか、どのように機能しているのか分かりません。私が聞いた1つのルールは、 "Qtはそれを世話します" - しかし、 "何のこと?"そして、何ではないのですか?

もちろん、私はQtの新機能ですが、QObjectのコンストラクタとデストラクタの数についていくつかの洞察があります。または、建設や破壊のそれぞれのメッセージ。そのような施設はQtにありますか?

+1

あなたのアプリがクラッシュしていないという事実は偶然であると私は信じています。これは、 'QObjects'がデストラクタの親のオブジェクトツリーから自分自身を削除するためです。スタック上であなたのウィジェットの構築順序を変更する場合、親が子の前に破壊されると、子を削除しようとしますが、その子はスタック上に作成されたので、SEGV –

+1

[オブジェクトツリーと所有権](http://doc.qt.io/qt-5/objecttrees.html)を参照してください。 – thuga

+0

@SteveLorimerは "親の木から自分自身を取り除く" ...そうです...それはうまくいくかもしれません。あなたは...私はthugaからのリンクを介してこれを読み上げます。 – towi

答えて

2

object trees and ownershipを見てみると、自動割り当てを使用するときは、作成する順番を気にする必要があります。 ローカルオブジェクトのデストラクタは、コンストラクタの逆順で呼び出されます。あなたの例ではそう

:ここ

int main(int argc, char **argv) { 
    QApplication app{argc, argv}; 
    QWidget window{}; 
    window.setWindowTitle("Der eine Knopf"); 
    QPushButton button{"Ende"}; 
    QObject::connect(&button, SIGNAL(clicked()), &app, SLOT(quit())); 
    QVBoxLayout layout{}; 
    layout.addWidget(&button); 
    window.setLayout(&layout); 
    window.show(); 
    return app.exec(); 
} 

あなたはwindowと呼ばれるQWidgetオブジェクトを作成します。次にQPushButtonを作成します。ウィジェットにレイアウトを設定し、そのレイアウトにbuttonを追加します。レイアウトは自動的にwindowを親としてbuttonに設定します。しかし、アプリケーションを終了してスコープが終了すると、buttonが最初に破棄されます。それが破壊されると、windowの子供の人のリストから削除されます。だから二度破壊されることはありません。あなたがwindowbuttonを作成する場合

はしかし、windowbutton前に破壊され、それはまた、それの子のすべてを破壊します。つまり、デストラクタをbuttonと呼ぶことになります。その後、範囲外になったので、buttonというデストラクタが再び呼び出されます。だからここに大きな問題があるだろう。