![](/img/trans.png)
[英]What is the correct way to write data to a file using worker thread in Qt?
[英]Qt: What is the correct and safe way to write the destructor of this class?
我在Windows7上使用Qt5,我最近发现了一个有趣的Qt示例代码 。
基本上,它看起来像这样:
ButtonWidget::ButtonWidget(const QStringList &texts, QWidget * parent)
: QWidget(parent)
{
signalMapper = new QSignalMapper(this);
QGridLayout * gridLayout = new QGridLayout;
for (int i = 0; i < texts.size(); ++i)
{
QPushButton * button = new QPushButton(texts[i]);
connect(button, SIGNAL(clicked()), signalMapper, SLOT(map()));
signalMapper->setMapping(button, texts[i]);
gridLayout->addWidget(button, i / 3, i % 3);
}
connect(signalMapper, SIGNAL(mapped(QString)), this, SIGNAL(clicked(QString)));
setLayout(gridLayout);
}
这是一个很好且有用的示例,但它没有正确的析构函数...以防万一我想要删除ButtonWidget
类型的对象,或者我想自定义代码以便能够删除/添加小部件。 这个想法是如何删除在构造函数中创建的所有对象(动态地,使用new
)。
我的方法是使用私有变量QList<QPushButton*> list
,将所有新分配的按钮添加到列表(在构造函数中)并使用上面的list
在析构函数中逐个删除它们。 但这似乎是幼儿园的方法。
我认为必须有其他方式,更好的方法来做到这一点,没有列表,没有搞乱构造函数代码:)感谢您的时间和耐心!
使用接收父作为其构造函数的参数的Qt类,例如QSignalMapper,重要的是要注意该类将其自身添加到其父对象列表中,并且当它的父(一个QObject)被破坏时它将被破坏。
因此,如果您将对象传递给父对象,则不必执行任何操作。 您可能在cpp文件中有一个空的析构函数,只是为了确保该成员的定义可用于QObject,但这取决于类。
但是,如果您确实选择编写自己的析构函数,那么正确实现的典型Qt“子”将在销毁时从其父级中删除。
除了标题/标题中提出的问题之外,OP还询问如果他想在删除父项之前删除子对象会发生什么:
瞄准以下内容 ,似乎(这是我自己的经验),他可能会删除子小部件,并且他们将自行删除。 已经提到过,可以将子节点的父节点设置为null,但这不是必需的,除非有人想要删除父节点并使子节点保持活动状态(重新父节点...)。
然而,如图中的最后一段例如 ,实例化的顺序是非常重要的。 如果在子节点之后实例化父节点,并且显式设置了子节点的父节点,则子节点将保留指向父节点的死引用/无效指针,并且当子节点尝试从子节点移除时,将发生未定义的行为。超出范围的父母。
除了Qt的文档之外 ,还可以在这里查看 QObject :: setParent的实现(setParent_helper) 。 由此可以看出,他们付出了巨大的努力,允许儿童/父母的删除没有发生意外,除了上述案例。
QWidget将获得布局的所有权。
来自QLayout::addItem
(由QLayout::addWidget
):
注意:项目的所有权转移到布局,布局负责删除它。
你不需要清理任何东西。 通过布局管理小部件
( addWidget
, removeWidget
/ removeItem
)。
你必须要看到它,你把你的所有小部件挂钩到Qt的对象树中 ,然后它会为你解决破坏问题。 你可以通过在构造它时给它一个父项来做到这一点。 就像你使用SignalMapper
。
没有“适当的”析构函数是不正确的。 有一个析构函数-一个由编译器生成-和析构函数做一切必要措施以释放资源。 它应该如何,这就是现代C ++代码的设计方式。
正确设计的C ++类应该可以使用,而无需显式管理其资源。 这就是这种情况。
此外,该示例不必要地动态分配可能只是类成员的成员。 在C ++ 11中,也不需要信号映射器。 我就是这样做的:
class ButtonWidget : public QWidget {
Q_OBJECT
QGridLayout m_layout { this };
public:
ButtonWidget(const QStringList &items, QWidget *parent = 0);
~ButtonWidget();
Q_SIGNAL void buttonClicked(const QString &);
}
ButtonWidget::ButtonWidget(const QStringList &items, QWidget *parent)
: QWidget(parent)
{
const int columns = 3;
for (int i = 0; i < items.size(); ++i) {
auto text = items[i];
auto button = new QPushButton(text);
connect(button, &QPushButton::clicked, [this, text]{
emit buttonClicked(text);
});
m_layout.addWidget(button, i / columns, i % columns);
}
}
ButtonWidget::~ButtonWidget() {}
这是一个完整,可用的小部件,没有内存泄漏。 这就是现代C ++ / Qt的外观。 如果你需要在析构函数中做一些奇特的事情,你应该总是考虑将内存管理分解为它自己的RAII类。 例如,不是手动关闭析构函数中的文件句柄,而是考虑使用QFile
,或者编写一个类似的资源管理类,然后可以使用它而不必担心手动管理句柄的生命周期。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.