Qt - 堆栈上具有父级的 QObject 如何被删除两次?
Qt - How a QObject with a parent on the stack might get deleted twice?
有人可以解释以下内容吗?
堆叠还是堆? 通常,应该在堆栈上创建没有父级的 QObject 或定义为另一个类的子对象。具有父级的 QObject 不应在堆栈上,因为这样它可能会意外删除两次。在堆上创建的所有 QObject 都应该有一个父对象,或者由另一个对象以某种方式管理。
来源:链接
抱歉,对接受的答案投反对票。目前解释的两个版本都是错误的,尤其是结论是非常错误的。
用于内存管理的父/子项
除此之外,Qt使用父/子概念来管理内存。当一个对象被父级化为另一个对象时,则
删除- 父项也将删除(通过
operator delete
)其所有子项。当然,这是递归的;
删除 - 子项将取消父级,以便父项不会尝试双重删除。
deleteLater
这不是工作所必需的 -任何删除都将取消父级。
这允许您通过operator new
重复动态分配来构建QObject
树,而不必手动删除所有分配的对象。只要给他们父母,你只需要删除树的根。您也可以随时删除子树(即子树),这将做正确的事情™。
最后,您将没有泄漏,也不会重复删除。
这就是为什么在构造函数中你会看到类似以下内容的原因:
class MyWidget : public QWidget // a QObject subclass
{
Q_OBJECT
public:
MyWidget(QWidget *parent = nullptr);
// default destructor is fine!
private:
// raw pointers:
// we won't own these objects through these pointers.
// we just need them to access the pointees
QTimer *m_timer;
QPushButton *m_button;
};
void MyWidget::MyWidget(QWidget *parent) : QWidget(parent)
{
// don't need to save the pointer to this child. because reasons
auto lineEdit = new QLineEdit(this);
auto validator = new QIntValidator(lineEdit); // a nephew
// but let's save the pointers to these children
m_timer = new QTimer(this);
m_button = new QPushButton(this);
// ...
}
默认析构函数将正确删除整个树,尽管我们通过调用operator new
分配了子对象,我们甚至懒得在成员中保存指向某些子对象的指针。
堆栈上的 Q
您可以(在某些情况下,这实际上是一个好主意)为堆栈上分配的对象提供父级。
典型的例子是QDialog
子类:
void MyWidget::showOptionsDialog()
{
// OptionsDialog is a QDialog subclass;
// create an instance as a child of "this" object
OptionsDialog d(this);
// exec the dialog (i.e. show it as a modal dialog)
conts auto result = d.exec();
if (result == QDialog::Accept) {
// apply the options
}
// d gets destroyed here
// => it will remove itself as a child of this
}
将this
作为对话框的父级传递的目的是允许对话框以父级的小组件为中心,共享任务托盘条目,并针对它进行模式处理。这在QDialog
文档中进行了解释。此外,最终,d
只需要存在于该函数中,因此最好将其声明为自动变量(即在堆栈上分配)。
好了:你有一个QObject
,在堆栈上分配,有一个父级。
那么堆栈上的QObject
有什么危险呢?请考虑以下代码:
QObject *parent = new QObject;
QObject child(parent);
delete parent;
如前所述,parent
这里将尝试在child
上调用operator delete
,一个未使用new
分配的对象(它在堆栈上)。这是非法的(并且可能崩溃)。
显然,没有人像这样编写代码,但再次考虑上面的对话框示例。如果在调用d.exec()
期间,我们设法以某种方式删除this
,即对话框的父级怎么办?这可能由于各种原因而发生,非常非常难以追踪 - 例如,数据到达套接字,导致UI中的小部件发生变化,创建一些并破坏其他小部件。最终,您将删除堆栈变量,崩溃(并且很难尝试重现崩溃)。
因此,建议首先避免创建这样的代码。它不是非法的,它可能有效,但也可能不起作用,没有人喜欢脆弱的代码。
- 如何从给定字符串中删除第二次和第三次出现的$
- g++的分段错误(在NaN上使用to_string两次时)
- 蛇在C++不会连续转两次
- 检查一个数组是否包含在另一个数组中,以相反的顺序,至少两次
- 从具有按值捕获的 lambda 移动构造 std::函数时,移动构造函数调用两次
- 我应该如何去缓解两次出现的cin?
- Realloc 两次无法在 Visual Studio 上运行
- 使用 getline(cin, var) 两次在进行字符串比较时会产生错误 (==)
- 为什么映射插入和 map.find() 的单次迭代比插入和 map.find() 的两次单独迭代慢得多
- 两个单链列表共享同一个节点和析构函数两次删除相同的内存
- 两次删除链表有什么区别?
- 有什么方法可以通过删除表达式安全地处理两次释放内存?
- 在 for 循环(链表)中删除两次后,变量不可用
- Qt - 堆栈上具有父级的 QObject 如何被删除两次?
- 删除对象两次
- C++-如果我使用映射,我的对象会被删除两次吗
- c++删除指针两次
- 重新分配变量,删除调用了两次(C++)
- 为什么当我删除两次相同的内存时没有错误?
- 为什么删除指针两次会导致崩溃