2017-05-11 12 views
1

動的にメモリを割り当てないこのコードは、ウィンドウにラベルを表示しません。動的メモリを割り当てた後QLabelにメモリを動的に割り当てる必要があるのはなぜですか?

MainWindow::MainWindow(QWidget *parent) 
    : QMainWindow(parent) 
{ 
    QLabel l; 
    l.setText ("cdsadsaf"); 
    l.setParent (this); 
} 

、ラベルが現れます。

MainWindow::MainWindow(QWidget *parent) 
    : QMainWindow(parent) 
{ 
    QLabel *label = new QLabel(this); 
    label->setText("first line\nsecond line"); 
} 

なぜ動的メモリ割り当てがQLabelが機能するために必要なのですか?

答えて

2

動的にメモリを割り当てないこのコードは、ウィンドウにラベルを表示しません。

これは、コンストラクタから返されるとすぐにラベルが有効範囲外になるためです。ラベルの寿命は以下のとおりです。 labelaQLabelです。動的メモリを割り当てた後

MainWindow::MainWindow(QWidget *parent) 
    : QMainWindow(parent) 
{ 
    QLabel label;    // label is born 
    label.setText ("cdsadsaf"); // label is alive 
    label.setParent (this);  // label is alive 
}        // label dies 

、ラベルが現れます。

これは、ラベルが有効範囲外にならないためです。それへのポインタは行いますが、それは問題ではありません。 labelは単なるポインタであり、QLabelオブジェクトはそのポインタとは独立して存在することに注意してください。

MainWindow::MainWindow(QWidget *parent) 
    : QMainWindow(parent) 
{ 
    QLabel *label = new QLabel(this);   // label is born, QLabel is born 
    label->setText("first line\nsecond line"); // label is alive, QLabel is alive 
}            // label dies, QLabel is alive 

なぜ動的メモリ割り当てがQLabelが機能するために必要なのですか?

そうではありません。ダイナミックアロケーションを使用した結果、QLabelに生き続ける機会が与えられましたが、これは単なる偶然のことです。

ラベルを親オブジェクトの一部にすることができます。別の割り当てを行う必要はありません。コンパイラがメモリを管理します。

#include <QtWidgets> 

class MainWindow : public QMainWindow { 
    QWidget m_central; 
    QGridLayout m_layout{&m_central}; 
    QLabel m_label{"Hello, World"}; 
public: 
    MainWindow(QWidget * parent = {}) : QMainWindow{parent} { 
    m_layout.addWidget(&m_label, 0, 0); 
    setCentralWidget(&m_central); 
    } 
}; 

int main(int argc, char ** argv) { 
    QApplication app{argc, argv}; 
    MainWindow w; 
    w.show(); 
    return app.exec(); 
} 
1

スタックにQLabelを作成すると、関数が返されると削除されます。親ウィジェットがそのディスプレイを更新するまでには、QLabelはもう存在しません。

ヒープ上に作成すると、関数の呼び出しを超えて存続することができます。

+1

なぜこれがダウン表示されますか? –

+1

"stack"という単語はC++標準のどこにもないので、何が起こるか記述する必要はありません。誰もが忘れそうなコンセプトは、** scope **です。オブジェクトは範囲外になり、存在しなくなります。それは**重要ではありません**どのようにC + +コンパイラは、スコープの外出を実装します。コンパイラは、互換性があり、すべての自動変数をヒープ上に配置するコードを生成することができます。スタックは何が起こっているのかを説明する必要はありません。実装の詳細です。 –

+0

@KubaOber、私はあなたの視点に感謝します。説明を追加していただきありがとうございます。 FWIW、C++ 11標準ではかなりの場所でスタックが記述されています。 –

5

必須ではありません。ここには典型的な範囲の問題があります。

最初のケースではスタックにQLabelが作成され、コンストラクタを終了すると「死んでしまいます。

動的に割り当てられているため1)動的に割り当てられているため2)実際に親を割り当てます。これがメインウィンドウです。 - あなたは)2を行わないと、効果は最初のケースが、悪いことと同じになりますが、メモリリークが作成されます:

メモリが漏れを

MainWindow::MainWindow(QWidget *parent) 
    : QMainWindow(parent) 
{ 
    QLabel *label = new QLabel(); # no parent 
    label->setText("first line\nsecond line"); 
} 

によるメモリリークラベル

MainWindow::MainWindow(QWidget *parent) 
    : QMainWindow(parent) 
{ 
    QLabel *label = new QLabel(this); # main window is the parent and will take care of destroying the label when its own destructor is called 
    label->setText("first line\nsecond line"); 
} 

に割り当てられている親にあなたはヒープ上QLabelを割り当てないと、まだ、まだちょうどより広い範囲にそれを移動することによって、それを使用することができます。ラベルはメインウィンドウに表示されるため、クラスメンバーラベルを作成できます。あなたのウィンドウインスタンスが生存している限り、動的な割り当ては必要ありません。あなたは、メモリ管理以外の何かのための親子関係を希望しない限り、コメントで述べたように

class MainWindow : public QMainWindow 
{ 
... 
private: 
    QLabel l; 
} 

MainWindow::MainWindow(QWidget *parent) 
    : QMainWindow(parent) 
{ 
    this->l.setText ("cdsadsaf"); 
} 

(おかげで再び!)setParent(...)が、ここで必要とされていません。以下のコメントを参照してください。

+0

クラスメンバであるウィジェットで 'setParent'を呼び出すと、それは2回削除されませんか?譲渡された親によって一度、通常のオブジェクト破壊の手段として一度?それは明らかにする価値があると思います。 –

+0

あなたは正しいです。コードをコピー&ペーストしたとき、その行を削除するのを忘れてしまった。 'delete'が呼び出され、スタックに割り当てられた何かを実行することが悪い動きであるため、実際にはすべての地獄が破られます。これを指摘してくれてありがとう! – rbaleksandar

+1

実際、それは問題ありません。子オブジェクトは、削除されると親オブジェクトとの関連付けが解除されます。 MainWindowが削除されると、メンバ変数のデストラクタが最初に呼び出されるので、 'l'は破壊される前に' MainWindow'から自身のリンクを解除するので、 'MainWindow'デストラクタが呼び出されると、' l'はもはやその子ではありません。しかし、それでも指摘する価値はあります。 [Qtドキュメント:オブジェクトツリー](http://doc.qt.io/qt-5/objecttrees.html) –

関連する問題