看Qt源码理解为什么布局类不用删除?

2020-06-24 15:35:42 浏览数 (1)

我们不妨看看以下小例子。

代码语言:javascript复制
QWidget window;
QPushButton *button1 = new QPushButton("One");
QPushButton *button2 = new QPushButton("Two");
QPushButton *button3 = new QPushButton("Three");

QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(button1);
layout->addWidget(button2);
layout->addWidget(button3);

window.setLayout(layout);
window.show();

qDebug() << "Window children:" << window.children();

  可以看到QPushButton和QHBoxLayout控件在new完后不需要执行delete操作。究竟是为何呢?我们再看看打印输出:

代码语言:javascript复制
Window children: (QHBoxLayout(0x1f32ebc0), QPushButton(0x1f48ea00), QPushButton(0x1f48e9c0), QPushButton(0x1f48e580))

  打印输出可以看到window对象下有QHBoLayout和3个QPushButton子控件,意味着当window对象析构时会先析构其下的所有子控件,所以就不需要手动删除了。

为了进一步验证,君君为大家奉上其Qt的实现源码。

  QWidget的setLayout源码中可以看到布局控件(QLayout)对象最终会设置自己的父类为QWidget。

代码语言:javascript复制
/* 省略部分无关代码 */
void QWidget::setLayout(QLayout *l)
{
    ...
    if (oldParent != this) {
        l->setParent(this);
        l->d_func()->reparentChildWidgets(this);
        l->invalidate();
    }
}

  QLayout的addWidget内部实现是传入的w对象最终也会设置其QLayout的parentWidget()对象。

代码语言:javascript复制
void QLayout::addWidget(QWidget *w)
{
    addChildWidget(w);
    addItem(QLayoutPrivate::createWidgetItem(this, w));
}

void QLayout::addChildWidget(QWidget *w)
{
    QWidget *mw = parentWidget();
    QWidget *pw = w->parentWidget();

    ...
    if (!pw && mw)
        w->setParent(mw);
    ...
}

  最后经过一轮花里胡哨的操作,最后QHBoxLayout和QPushButton控件都有一个共同的父类就是window

相关知识

  在Qt中,每个QObject内部都有用来保存所有的子对象列表(children),同时还会保存自己的父对象(parent)。当它自己析构时,它会将自己从父对象(parent)的列表中删除,并且析构掉所有的子对象列表(children)。

看Qt源码理解半自动内存管理

0 人点赞