根据Qt文档:
QObjects在对象树中组织自己.当您使用另一个对象作为父对象创建QObject时,该对象将自动将其自身添加到父对象的children()列表中.父母取得对象的所有权; 即,它将自动删除其析构函数中的子项.
对于我来说,这意味着当一个QObject被删除时,它会通过并在它存储在子列表中的所有指针上调用delete.
但是,没有必要动态分配子项,并且使用堆栈分配的对象构建QObject树是完全合法的.
根据标准规范,对未指向动态分配对象的指针调用delete是未定义的行为,这可能导致从"无"到程序崩溃的任何内容.
IMO不太可能是QObject,它几乎是几乎整个Qt类集合的主干,依赖于可能产生未定义行为的东西.
那么,QObject在删除时是否区分堆栈和堆分配子项?如果是这样,究竟是怎么回事?
在这里提出这个问题之前,我已经想了很多并阅读了很多文章.这些文章都没有给我一个正确的答案.
http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/
QThread* thread = new QThread;
Worker* worker = new Worker();
worker->moveToThread(thread);
connect(worker, SIGNAL(error(QString)), this, SLOT(errorString(QString)));
connect(thread, SIGNAL(started()), worker, SLOT(process()));
connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
Run Code Online (Sandbox Code Playgroud)
Worker对象具有新线程的亲和力.
1> Worker完成信号将调用线程上的quit().这将结束线程的事件循环并启动线程完成信号.
2> Worker完成信号连接到worker deleteLater().根据deleteLater()文档
**安排此对象删除.当控制返回到事件循环时,将删除该对象.如果事件循环>未运行
当调用此函数时(例如,在QCoreApplication :: exec()之前在对象上调用deleteLater()),一旦启动事件循环,该对象将被删除.
注意,进入和离开新的事件循环(例如,通过打开模态对话框)将不执行延迟删除; 对于要删除的对象,控件必须返回到调用deleteLater()的事件循环.
注意:不止一次调用此函数是安全的; 在传递第一个延迟删除事件时,将从事件队列中删除该对象的任何挂起事件.**
因此,当没有eventloop时,由于线程已经退出并且它已经提升了完成的信号,我们将不再再次启动相同的线程.在这种情况下,将永远不会处理deleteLater(),因为事件循环不存在,并且根本不会删除worker对象.这不会造成内存泄漏吗?
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
Run Code Online (Sandbox Code Playgroud)
如果我们认为交换这两行将解决问题,那么我还有另外一个问题.QT明确指出,在发出信号时调用插槽的顺序是不确定的
上面提到的文章链接中有很多评论.即便是作者也无法完全回答这个问题
我查看了相关的问题,找不到任何能解决我所说的内容的内容,所以让我来描述一下.
我有一个类,让我们说foo需要有自己的插槽和信号,但也需要从QXmlDefaultHandler继承(听起来很奇怪,但我在尝试使用QHttp将网站直接读入QBuffer时遇到了这种情况).
class foo: public QXmlDefaultHandler, public QObject
{
public:
foo();
~foo();
Q_OBJECT
public slots:
void bar();
}
Run Code Online (Sandbox Code Playgroud)
这个代码,如果附带一个cpp连接条到其他地方的信号,将无法编译.您将获得有关QObject的某些成员不是QXmlDefaultHandler成员的错误.另外,你不能移动Q_OBJECT,否则你会因为没有实现某些东西而得到vtable错误(继续!试试吧!).
请看(非常简单)修复我的答案.如果我认为你比我更好地解释它,我会接受投票给你作为公认的答案.
编辑:对于你c ++和Qt兽医,如果你能更好地解释它,请发一个答案.我花了很多时间查看这些信息,所以如果你能做得比我好,请帮助别人.
对于我的一个项目,我有一个QObject派生对象树,它利用QObject的父/子功能来构建树.
这非常有用,因为我使用了信号和插槽,使用Qt的保护指针并期望父对象在删除时删除子对象.
到现在为止还挺好.不幸的是,现在我的项目要求我管理/改变孩子的顺序.QObject没有提供任何改变其子节点顺序的方法(例外:QWidget的raise()函数 - 但在这种情况下这没用).所以现在我正在寻找一种控制孩子秩序的策略.我有一些想法,但我不确定他们的利弊:
使用int m_orderIndex成员变量作为排序键,并提供一个sortedChildren()方法,该方法返回按此键排序的QObject列表.
QObject::children()方法被覆盖时会出现问题 - 当项目的顺序发生变化时,在循环期间会导致问题,也比默认实现更昂贵.在a中维护一个冗余的子项列表QList,并在创建和销毁子项时添加子项.
任何想法或反馈,特别是那些已经在自己的项目中解决过这个问题的人,都会受到高度赞赏.新年快乐!
我很好奇QObject究竟有多大,包括每个实例动态创建的典型私有数据.sizeof由于它们的实施方式,我无法得到那些.
编辑:请注意,我问的QObject的典型使用场景的大小,我不是问"如何获得大小"这是其他问题的关键,我问的是谁知道大概的大小,因为很明显,语言本身并没有提供报告的方法.
我的原始代码将QStringList从信号传递到插槽,然后返回一个QList.一切正常但我需要将QStringList和QList更改为2个不同的子类QObject.从那时起,我一直收到像"首先需要的合成方法"这样的错误,或者只是崩溃而没有任何错误信息.
我知道qt复制了排队连接中传递的所有参数,并且无法复制qobject.所以我没有返回一个qobject,而是认为我会在发出信号之前创建两个qobjects.然后我将传递对每个对象的引用,在slot函数中修改其中一个并使返回值无效.不幸的是,无论我如何编码信号和插槽功能,应用程序仍会崩溃.如何编码信号/插槽函数并将它们连接到两个qobjects作为参数或返回一个qobject?
MyQObject1 obj1("a","b","c");
MyQObject2 obj2();
emit sendSignal(&obj1, &obj2);
// or
MyQObject2 obj2 = emit sendSignal(&obj1);
connect(someObj, SIGNAL(sendSignal(const QObject&)), this, SLOT(receiveSignal(const QObject&)));
Run Code Online (Sandbox Code Playgroud)
receiveSignal()函数不直接创建或修改任何qobject.它必须首先将qobjects传递给另一个函数,然后修改obj2或创建并返回它.任何代码示例将不胜感激.
至于将C++类型的属性暴露给与QML一起使用的QML类必须是QObjects.我有可能使用非QObjectss(又名POCO,不是从QObjectQt元系统中派生出来的,而是注册的)
如果没有,是否有一个简单的通用包装系统,使我的对象符合QML.我能想到的是将动态属性添加到简单的属性中QObject.
或者有没有办法隐式转换为QML兼容类型,所以我根本不需要包装?
QObjectQML 引入了与可视化树(QtQuick 场景图)分离的所有权 ( ) 树。
parent返回视觉父级。children返回视觉儿童。data返回QObject孩子们。但是我如何访问QObject父级呢?
仅供参考,我打算动态创建和销毁包含自定义类型的嵌套布局,因此我需要管理树QObject- 仅使用可视树将导致“错误”对象在重新设置父级然后删除后消失。
我有一个名为MiscData继承QObject并具有成员变量(模型)的类。然后是一堆继承MiscData并重新实现其虚函数来填充模型的其他类。所以它看起来像这样:
class MiscData : public QObject
{
Q_OBJECT
public:
explicit MiscData(QObject *parent = 0);
QAbstractItemModel &model();
private:
virtual void loadData() = 0;
private:
QStandardItemModel m_Model;
}
Run Code Online (Sandbox Code Playgroud)
其中一个后代看起来像这样:
class LogData : public MiscData
{
Q_OBJECT
public:
using MiscData::MiscData;
private:
virtual void loadData() override;
}
Run Code Online (Sandbox Code Playgroud)
我知道我必须使用显式构造函数,MiscData因为它初始化模型成员变量。using但我想知道在派生类中使用指令来继承MiscData这样的构造函数是否安全。
using QObject::QObject编辑:根据答案,在 MiscData 中使用似乎也是很好的事件。
所以我知道如何将QML属性绑定到C++属性,所以当C++调用notify信号时,QML会更新视图.当用户使用UI更改内容时,有没有办法使C++属性更新?
例如,我有一个Combobox,我希望在用户更改组合框的值时更新一些C++属性.
编辑:通过C++属性我的意思是Q_PROPERTY宏QObject来源的类.