2011-07-14 15 views
2

Qtが新しくなりました。だから私は始めの例の一つを再実装し始めた:linkなぜこのQTアプリはSIGABRTシグナルで終了しますか?

しかし、ウィンドウを閉じるときにSIGABRTシグナルが表示されます。この理由は、何らかのメモリ管理エラーによるものです。

以下に、コールスタックと関連するコードを示します。行editWindow.setLayout(&layout);がエラーを引き起こします。レイアウトクラスは破壊時にウィジェットを削除しているので、ウィジェットの所有権を主張していますか?

この現象の原因は何ですか?それを修正する方法は?

よろしくお願いいたします。

情報
コールスタック
callstack

ソース

QPushButton testButton("Test"); 

    QVBoxLayout layout; 
    layout.addWidget(&testButton); 

    QWidget editWindow; 
    // the following line is the source of the error 
    editWindow.setLayout(&layout); 
    editWindow.show(); 

    int val = app.exec(); 

答えて

7

多くの異なるQtの機能は、それがすべてのメモリ管理の制御を前提とし、削除時にそれを解放することを意味渡されます。 setLayoutからdocs:

QWidgetはレイアウトの所有権を取得します。

setLayoutを呼び出した後、それには親があり、その親はそれを削除しますが、メソッドのスタックがクリーンアップされたときに削除されます。したがって、それは問題を引き起こしている2回削除されています。

他のすべてが正しい場合、この変更は、それを修正する必要があります

QVBoxLayout *layout = new QVBoxLayout(); 
//... 
layout->addWidget(&testButton); 
//... 
editWindow.setLayout(layout); 

また、それがメインウィジェットを作成し、親としてそのウィジェットに表示されるウィジェットを割り当てるための典型的だということに注意してください。言い換えれば、私は次のようなものをもっと期待しています(厳密には必要ではありませんが)。また、これは何かが将来的に再ペアレントてしまった場合は、問題を抱えていないことを保証するのに役立ちます。

QWidget editWindow; 
QVBoxLayout *layout = new QVBoxLayout(); 
QPushButton *testButton = new QPushButton(&editWindow); 
layout->addWidget(testButton); 
editWindow.setLayout(layout); 
editWindow.show(); 
int val = app.exec(); 

ほとんどのQt再ペアレント化されたオブジェクトとを、所有権の変更がQWidget*またはQObject*を受け取るコンストラクタを持つことになりますが起こる可能性があると。

+0

この非常に良い答えに感謝します。 – Velrok

2

QWidgetは、new演算子を経て作成したレイアウトのインスタンスを期待して、インスタンスの所有権を取得、ときに削除を呼び出しますQWidgetが破棄されます(see documentation)。所有権と同じことがあなたのtestButtonに適用

QVBoxLayout *layout = new QVBoxLayout(); 
/// ... 
editWindow.setLayout(layout); 

:そのために何が必要このようなものです。

+0

レイアウトはボタンの所有権を取らないので、パーツは問題ないはずですが、ウィジェットを再作成し、そのクリーンアップを制御する何かをしないように注意する必要があります。 –

+0

ドキュメントによると、レイアウトのaddWidgetメソッドは、渡されたインスタンスの所有権を取得するaddItemを内部的に使用します。[documentation](http://doc.qt.nokia.com/4.7/qlayout.html#addItem)を参照してください。 – mike

+0

ドキュメントは、実際には、「** item **の所有権はレイアウトに転送されます」、itemは 'addWidget'に渡されたQWidgetではなく、functionパラメータで定義された' QLayoutItem'です。私はこれを明示的にテストしたことはありませんが、私はそれとは反対に何も見たことがありません。あなたがテストして見つけたら、私に知らせてください。 –

1

例のコードが間違っているようです(奇妙なことです)。 QWidgetのデストラクタは、そのレイアウト上でdeleteを呼び出します。あなたのケースでは、QVBoxLayoutインスタンスがヒープではなくスタック上に作成されているため、そのポインタのdeleteを無効にするとアプリケーションが異常終了します。

QObjectのすべての子供に同じです。 QObjectが削除されると、すべての子に対してdeleteが呼び出され、それらの子がスタックに作成されている場合、同じ方法で失敗します。ノキアは、このような悪い例を掲載する理由

、理解するために...オブジェクトの所有権を取得します

関連する問題