在堆栈上创建QLayout是否安全?

时间:2012-05-01 14:41:28

标签: c++ qt

我知道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,也会产生未定义的行为。这是真的吗?

2 个答案:

答案 0 :(得分:4)

每个QObject删除其子级。只有没有父级的对象才能拥有自动存储。 QWidget::setLayout重新布局。所以,不,你不能用QLayout来做到这一点。

答案 1 :(得分:1)

在Qt中,对象树的设计使得QWidgets可以在堆栈上构建。只要父母在孩子面前被创造,他们就会彻底毁灭。你的例子都没有未定义的行为。

Qt文档甚至是gives an example,并解释了为什么在堆栈中构建包含父项的小部件是合法的:

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

此代码是正确的:退出的析构函数不会被调用两次,因为C ++语言标准(ISO / IEC 14882:2003)指定以与构造函数相反的顺序调用本地对象的析构函数。因此,首先调用子的析构函数quit,并在调用窗口的析构函数之前将其从父窗口中移除。

布局也应该正常运行,因为它们可以随时被销毁。 QWidget::setLayout documentation提及:

  

如果此窗口小部件上已安装布局管理器,QWidget将不允许您安装另一个布局管理器。您必须首先删除现有布局管理器(由layout()返回),然后才能使用新布局调用setLayout()。

Qt布局系统跟踪已在QWidgets上设置的QLayout对象的生命周期,并将适当地处理破坏,如本文档所暗示的。 QLayout的析构函数包含从设置它的QWidget中取消注册它的代码。