我知道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
,也会产生未定义的行为。这是真的吗?
答案 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中取消注册它的代码。