Ice*_*ire 1 c++ qt memory-management
通常,在编写 C++ 代码时,我会将对象始终作为普通属性保存,从而利用 RAII。然而,在 QT 中,删除对象的责任可以在QObject
. 所以,假设我们定义了一些特定的小部件,那么我们有两种可能性:
1)使用QT的系统
class Widget1 : QWidget
{
Q_OBJECT
public:
Widget1(QWidget* parent = nullptr);
private:
QPushButton* myButton; // create it with "new QPushButton(this);"
};
Run Code Online (Sandbox Code Playgroud)
2)使用RAII
class Widget2 : public QWidget
{
Q_OBJECT
public:
Widget2(QWidget* parent = nullptr);
private:
QPushButton button; // normal RAII
};
Run Code Online (Sandbox Code Playgroud)
通常,我使用第一种方法。如果父母不仅通过布局了解其孩子,似乎有些事情会更好。但是仔细想想……真正的原因我还不是很清楚。
我知道堆栈是有限的。但是,假设这在这里不起作用。毕竟,堆栈不是那么小。
如果父母不仅通过布局了解其孩子,似乎有些事情会更好。
你是对的。AQObject
的父级不仅用于内存管理目的,这个答案总结了它的一些其他用法。这里最重要的是QWidget
's的那些(因为您关心添加成员QWidget
的),所以如果您按照编写它的方式使用第二种方法,以下是您可能会遇到的一些问题:
假设您正在Widget1
像这样在主函数中实例化和显示它:
Widget1 w;
w.show();
Run Code Online (Sandbox Code Playgroud)
这将显示一个空的小部件,其中没有按钮。与 whenbutton
是Widget1
对象的子级的行为相反,调用show()
显示窗口小部件父级及其所有子级在里面。
使用setEnabled()
, setLayoutDirection()
, ...时会发生类似的问题
button.pos()
不会返回相对于 的坐标Widget1
,实际上按钮甚至没有显示在里面。使用move()
.
事件系统可能无法按预期工作。因此,如果成员小部件不处理某些鼠标/键盘事件,则该事件不会传播到父小部件(因为没有指定父小部件)。
但是可以编写第二种方法来利用与 RAII 的父关系,从而避免上述问题:
class Widget2 : public QWidget
{
public:
explicit Widget2(QWidget* parent = nullptr):QWidget(parent){}
private:
QPushButton button{this}; //C++11 member initializer list
};
Run Code Online (Sandbox Code Playgroud)
或者,在 C++11 之前的版本中:
class Widget2 : public QWidget
{
public:
//initialize button in constructor, button's parent is set to this
explicit Widget2(QWidget* parent = Q_NULLPTR):QWidget(parent), button(this){}
private:
QPushButton button;
};
Run Code Online (Sandbox Code Playgroud)
这样,两种方法之间的 Qt 框架就没有任何区别。事实上,使用第二种方法可以避免不必要的动态分配(请注意,如果分配在某些嵌套循环中非常频繁地执行,例如,这可能会稍微提高性能。但是,对于大多数应用程序,性能在这里并不是真正的问题)。因此,您可能会像这样编写小部件:
class Widget : public QWidget
{
public:
explicit Widget(QWidget* parent = nullptr):QWidget(parent){
//add widgets to the layout
layout.addWidget(&button);
layout.addWidget(&lineEdit);
layout.addWidget(&label);
}
~Widget(){}
private:
//widget's layout as a child (this will set the layout on the widget)
QVBoxLayout layout{this};
//ui items, no need to set the parent here
//since this is done automatically in QLayout::addWidget calls in the constructor
QPushButton button{"click here"};
QLineEdit lineEdit;
QLabel label{"this is a sample widget"};
};
Run Code Online (Sandbox Code Playgroud)
这很好,有人可能会说这些子小部件/对象将被销毁两次,第一次是在它们超出范围时,第二次是在它们的父级被销毁时,使这种方法不安全。这不是问题,因为一旦子对象被销毁,它就会将自己从其父对象的子对象列表中删除,请参阅文档。因此,每个对象只会被销毁一次。
归档时间: |
|
查看次数: |
944 次 |
最近记录: |