3

我从 Qt 文档中知道该QLayout对象承担其小部件的所有权。但就对象而言,在堆栈上创建它然后使用该函数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

每个QObject删除它的孩子。只有没有父对象的对象才能具有自动存储。并QWidget::setLayout重新定义布局。所以,不,你不能用QLayout.

于 2012-05-01T14:49:33.170 回答
1

在 Qt 中,对象树的设计使得 QWidgets 可以在堆栈上构建。只要父母是在孩子之前被创造出来的,他们就会正确地毁灭。您的两个示例都不是未定义的行为。

Qt 文档甚至给出了一个示例并解释了为什么在堆栈上构造带有父级的小部件是合法的:

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

这段代码是正确的:quit 的析构函数没有被调用两次,因为 C++ 语言标准 (ISO/IEC 14882:2003) 指定本地对象的析构函数按其构造函数的相反顺序调用。因此,首先调用子进程的析构函数quit,然后在调用window 的析构函数之前将自己从其父window 中移除。

布局也应该正常运行,因为它们被设计为随时被销毁。QWidget::setLayout 文档提到:

如果这个小部件上已经安装了布局管理器,QWidget 不会让你安装另一个。您必须先删除现有的布局管理器(由 layout() 返回),然后才能使用新布局调用 setLayout()。

Qt 布局系统跟踪已在 QWidgets 上设置的 QLayout 对象的生命周期,并将适当地处理销毁,如本文档所暗示的那样。QLayout 的析构函数包括将其从设置的 QWidget 中注销的代码。

于 2012-05-01T18:42:17.707 回答