在堆栈上创建 QLayout 是否安全

Is it safe to create a QLayout on the stack?

本文关键字:是否 安全 QLayout 创建 堆栈      更新时间:2023-10-16

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

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

在Qt中,对象树的设计使得QWidgets可以在堆栈上构建。只要父母先于孩子被创造,他们就会正确地破坏。你的两个例子都不是未定义的行为。

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

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

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

布局也应该表现正常,因为它们被设计为随时被破坏。QWidget::setLayout文档提到:

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

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