Qt智能指针--QSharedPointer

139 篇文章 179 订阅

前言

Qt智能指针QSharedPointer 与 C++中的std::shared_ptr其作用是一样的,其应用范围比我们前面说到的QPointerQScopedPointer更广。

QSharedPointer

QSharedPointer 是一个共享指针,它与 QScopedPointer 一样包装了new操作符在堆上分配的动态对象,但它实现的是引用计数型的智能指针 ,也就是说,与QScopedPointer不同的是,QSharedPointer可以被自由地拷贝和赋值,在任意的地方共享它,所以QSharedPointer也可以用作容器元素。

所谓的计数型指针,就是说在内部QSharedPointer对拥有的内存资源进行引用计数,比如有3个QSharedPointer同时指向一个内存资源,那么就计数3,知道引用计数下降到0,那么就自动去释放内存啦。

需要注意的是:QSharedPointer 是线程安全的,因此即使有多个线程同时修改 QSharedPointer 对象也不需要加锁。虽然 QSharedPointer 是线程安全的,但是 QSharedPointer 指向的内存区域可不一定是线程安全的。所以多个线程同时修改 QSharedPointer 指向的数据时还要应该考虑加锁。

先来看一个官方示例:

	static void doDeleteLater(MyObject *obj)
    {
        obj->deleteLater();
    }

    void otherFunction()
    {
        QSharedPointer<MyObject> obj =
            QSharedPointer<MyObject>(new MyObject, doDeleteLater);

        // continue using obj
        obj.clear();    // calls obj->deleteLater();
    }

这个示例中,传入了一个函数,用于自定义删除。

也可以直接使用成员函数:

QSharedPointer<MyObject> obj =
        QSharedPointer<MyObject>(new MyObject, &QObject::deleteLater);

QSharedPointer使用非常方便,直接和普通指针用法一样,创建后直接用,后面就不用管了。

再来看一个自己写的简单示例:

class Student : public QObject
{
    Q_OBJECT
public:
    Student(QObject * parent = nullptr);
    ~Student();
};

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = 0);
    ~Widget();
private:
    QSharedPointer<Student> m_pStudent;

};

#include "widget.h"
#include <QDebug>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    qDebug() << __FUNCTION__;
    m_pStudent = QSharedPointer<Student>(new Student());
}

Widget::~Widget()
{
    qDebug() << __FUNCTION__;
}

Student::Student(QObject *parent):
    QObject (parent)
{
    qDebug() << __FUNCTION__;
}

Student::~Student()
{
    qDebug() << __FUNCTION__;
}

运行后关闭窗口,输出:

Widget
Student
~Widget
~Student

可以看到,student对象被自动释放了。

值得一提

我们都知道Qt的QObject对象树系统(父子),当在创建对象时如果指定了父对象,那么该对象就无需手动释放,会由父对象去做资源回收。我在查询智能指针相关资料的时候,看到一篇文章,介绍智能指针和QObject对象树系统结合使用的时候,程序会崩溃,文章在这里,不过这是六年前的博客了。我尝试了一下,结果并没有出现崩溃的情况:

还是上面的示例,改动如下:

m_pStudent = QSharedPointer<Student>(new Student(this));

在new的时候指定了父对象

运行过后关闭窗口,很正常。我使用的是Qt5.11.1

说明,这些年Qt的更新解决了这个问题。那么我们在用的过程中就可以少些顾虑了,放心使用。

OK,更多文档说明,参考官方介绍

  • 29
    点赞
  • 110
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
Qt智能指针--QWeakPointer ⽂章⽬录 概述 前⾯我们说到的是⼀个强引⽤类型的智能指针,⽽QWeakPointer是⼀个弱引⽤类型的智能指针,和C++中的weak_ptr功能是⼀样的。 QWeakPointer 是为配合 QSharedPointer ⽽引⼊的⼀种智能指针,它更像是 QSharedPointer 的⼀个助⼿(因为它不具有普通指针的⾏ 为,没有重载operator*和->)。它的最⼤作⽤在于协助 QSharedPointer ⼯作,像⼀个旁观者⼀样来观测资源的使⽤情况。 QWeakPointer QWeakPointer不能⽤于直接取消引⽤指针,但它可⽤于验证指针是否已在另⼀个上下⽂中被删除。并且QWeakPointer对象只能通过 QSharedPointer的赋值来创建。 需要注意的是,QWeakPointer不提供⾃动转换操作符来防⽌错误发⽣。即使QWeakPointer跟踪指针,也不应将其视为指针本⾝,因为它 不能保证指向的对象保持有效。 说了那么多,QWeakPointer到底有什么⽤呢? 答案就是:解除循环引⽤。 在概述中我们说到,QWeakPointer 是为配合 QSharedPointer ⽽引⼊的⼀种智能指针。⽽什么叫循环引⽤,就是说:两个对象互相使⽤ ⼀个 QSharedPointer成员变量指向对⽅(你中有我,我中有你)。由于QSharedPointer是⼀个强引⽤的计数型指针,只有当引⽤数为0 时,就会⾃动删除指针释放内存,但是如果循环引⽤,就会导致QSharedPointer指针的引⽤永远都不能为0,这时候就会导致内存⽆法释 放。 所以QWeakPointer诞⽣了,它就是为了打破这种循环的。并且,在需要的时候变成QSharedPointer,在其他时候不⼲扰 QSharedPointer的引⽤计数。它没有重载 * 和 -> 运算符,因此不可以直接通过 QWeakPointer 访问对象,典型的⽤法是通过 lock() 成 员函数来获得 QSharedPointer,进⽽使⽤对象。 ⽰例 ⾸先,我们来看⼀个QSharedPointer循环使⽤的⽰例: #include <QWidget> #include <QDebug> #include <QWeakPointer> #include <QSharedPointer> class Children; class Parent { public: ~Parent(){ qDebug() << __FUNCTION__; } QSharedPointer<Children> m_pChildren; }; class Children { public: ~Children(){ qDebug() << __FUNCTION__; } QSharedPointer<Parent> m_pParent; }; class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = 0); ~Widget(); void test(); }; #include "widget.h" Widget::Widget(QWidget *parent) : QWidget(parent) { test(); } Widget::~Widget() { qDebug() << __FUNCTION__; } void Widget::test() { QSharedPointer<Parent> parent(new Parent()); QSharedPointer<Children> children(new Children()); if(parent && children){ parent->m_pChildren = children; children->m_pParent = parent; } } 在构造函数中调⽤test()函数,执⾏完过后应该会⾃动释放parent和children对象,但是由于相互引⽤,在退出之前,引⽤计数为2,退出 之后引⽤计数还是1,所以导致不能⾃动释放,并且此时这两个对象再也⽆法访问到。运⾏过后发现并没有进⼊到Parent和Children的析构 函数中。这就导致了内存泄漏。 那么该如何解决这个问题呢? 很简单,直接将上述代码中的 QSharedPointer<Children> m_pChildren; QSharedPointer<Parent> m_pParent; 改成 QWeakPointer<Children> m_pChildren; QWeakPointer<Parent> m_pParent; 这时候
### 回答1: 是的,Qt5.15.2 QML 可以支持 QSharedPointer 类型的智能指针注册,并在 QML 中使用。 首先,你需要使用 `qmlRegisterUncreatableType()` 函数将 QSharedPointer 注册为不可创建的类型。在注册时,你需要提供一个类型名和所有者类型。所有者类型是智能指针所拥有的类型,可以是任何 QObject 派生类型。以下是注册 QSharedPointer 的示例代码: ```cpp qmlRegisterUncreatableType<QSharedPointer<MyObject>>("MyApp", 1, 0, "SharedPtr", "QSharedPointer cannot be created in QML"); ``` 在 QML 中,你可以使用 `SharedPtr` 类型来声明一个 QSharedPointer 实例。例如: ```qml import MyApp 1.0 Item { property SharedPtr obj: SharedPtr.createObject() Component.onCompleted: { obj.data.name = "Hello World" } } ``` 在上面的例子中,我们声明了一个名为 `obj` 的 `SharedPtr` 属性,并在 `Component.onCompleted` 信号中给 `obj` 所指向的对象赋值。请注意,我们使用 `data` 成员来访问 QSharedPointer 中的对象。 需要注意的是,当在 QML 中使用 QSharedPointer 时,你需要小心管理所有权。通常情况下,你应该避免将 QSharedPointer 实例传递给 QML,因为 QML 中的对象生命周期管理可能会与 C++ 中不同。相反,你可以将 QSharedPointer 实例封装在一个 QObject 派生类型中,并将该类型注册为可创建类型,然后在 QML 中创建该类型的实例。例如: ```cpp class MyObjectWrapper : public QObject { Q_OBJECT Q_PROPERTY(QSharedPointer<MyObject> obj READ obj WRITE setObj NOTIFY objChanged) public: QSharedPointer<MyObject> obj() const { return m_obj; } void setObj(QSharedPointer<MyObject> obj) { if (m_obj != obj) { m_obj = obj; emit objChanged(); } } signals: void objChanged(); private: QSharedPointer<MyObject> m_obj; }; qmlRegisterType<MyObjectWrapper>("MyApp", 1, 0, "MyObjectWrapper"); ``` 现在,在 QML 中,你可以使用 `MyObjectWrapper` 类型来声明一个包含 QSharedPointer 实例的对象。例如: ```qml import MyApp 1.0 MyObjectWrapper { obj: SharedPtr.createObject() } ``` 在这种情况下,你可以安全地将 `MyObjectWrapper` 实例传递给 QML,并在 QML 中使用 QSharedPointer 实例。 ### 回答2: 是的,Qt5.15.2的QML可以支持QSharedPointer类型的智能指针注册和在QML中使用。在注册类型时,您可以使用qmlRegisterUncreatableType()函数将QSharedPointer类型注册为不可创建的类型,以防止在QML中直接创建该类型的对象。例如,您可以这样注册QSharedPointer<MyObject>类型: ```cpp qmlRegisterUncreatableType<QSharedPointer<MyObject>>("CustomTypes", 1, 0, "SharedPointer", "Cannot create objects of type SharedPointer in QML"); ``` 在上述代码中,我们将QSharedPointer<MyObject>注册为名为SharedPointer的不可创建类型,并将其命名空间定义为"CustomTypes",版本为1.0。 然后,在QML文件中,您可以使用该类型,例如: ```qml import CustomTypes 1.0 Item { id: root property SharedPointer myObject: SharedPointer.createObject() Component.onCompleted: { myObject.data.someProperty = "Hello" console.log(myObject.data.someProperty) // 输出 "Hello" } } ``` 上面的例子中,我们创建了一个名为myObject的SharedPointer实例,并将其属性设置为一个新的MyObject实例。然后,在Completed信号中,我们可以访问和修改myObject中MyObject实例的属性。 因此,通过使用qmlRegisterUncreatableType()将QSharedPointer类型注册为不可创建的类型,并在QML中使用SharedPointer属性,您可以在Qt5.15.2的QML中使用QSharedPointer类型的智能指针。 ### 回答3: Qt 5.15.2 QML可以支持QSharedPointer类型的智能指针注册,并可以在QML中使用。 QSharedPointerQt提供的一种智能指针类型,用于管理动态内存分配。它可以在堆上创建对象,并在不再需要时自动释放内存,从而避免了内存泄漏和野指针等问题。 为了在QML中使用QSharedPointer类型的智能指针,我们需要进行一些注册和转换操作。首先,我们需要在C++代码中将QSharedPointer注册为一个可以在QML中访问的类型。可以使用qmlRegisterType函数将QSharedPointer注册为QML类型,使其在QML中可以实例化和调用其方法。 在C++代码中,我们可以这样注册QSharedPointer: ```cpp qmlRegisterType<QSharedPointer<MyObject>>("MyModule", 1, 0, "MyObject"); ``` 这样就将QSharedPointer<MyObject>类型注册为MyModule.MyObject类型,可以在QML中使用。 在QML中,我们需要使用QtObject作为QSharedPointer对象的包装器。可以通过编写一个C++插件来实现。 ```cpp // MyObjectWrapper.h #ifndef MYOBJECTWRAPPER_H #define MYOBJECTWRAPPER_H #include <QObject> #include <QSharedPointer> class MyObject; class MyObjectWrapper: public QObject { Q_OBJECT public: explicit MyObjectWrapper(QObject *parent = nullptr); ~MyObjectWrapper(); QSharedPointer<MyObject> getObject() const; void setObject(QSharedPointer<MyObject> object); private: QSharedPointer<MyObject> m_object; }; #endif // MYOBJECTWRAPPER_H ``` ```cpp // MyObjectWrapper.cpp #include "MyObjectWrapper.h" #include "MyObject.h" MyObjectWrapper::MyObjectWrapper(QObject *parent) : QObject(parent) { } MyObjectWrapper::~MyObjectWrapper() { } QSharedPointer<MyObject> MyObjectWrapper::getObject() const { return m_object; } void MyObjectWrapper::setObject(QSharedPointer<MyObject> object) { m_object = object; } ``` 然后在QML中使用这个包装器: ```qml import MyModule 1.0 QtObject { property MyModule.MyObject myObject: MyModule.MyObjectWrapper { object: createMyObject() // 通过工厂函数创建MyObject对象 }.object } ``` 以上代码在QML中创建了一个QtObject对象,其属性myObject是一个MyObject对象的QSharedPointer。createMyObject()可以是一个工厂函数,用于创建MyObject对象。 以上就是Qt 5.15.2 QML如何支持QSharedPointer类型的智能指针注册,并在QML中使用的方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

luoyayun361

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值