Qt智能指针--QSharedPointer

前言

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,更多文档说明,参考官方介绍

### Qt 智能指针与信号槽机制 在Qt框架中,智能指针能够有效管理内存并防止资源泄漏。当结合信号槽机制时,可以创建更加健壮的应用程序结构。 #### 创建带有智能指针的类实例 为了展示如何将智能指针应用于发射器和接收者对象,在下面的例子中使用`QSharedPointer`来持有两个自定义类型的共享所有权: ```cpp #include <QObject> #include <QSharedPointer> class SignalEmitter : public QObject { Q_OBJECT public: explicit SignalEmitter(QObject* parent = nullptr); signals: void dataChanged(const QString& message); }; class SlotReceiver : public QObject { Q_OBJECT public slots: void onDataReceived(const QString& msg) { qDebug() << "Message received:" << msg; } }; ``` #### 连接信号与槽函数 通过智能指针初始化上述两类对象,并利用`connect()`方法建立两者之间的联系。这里需要注意的是,由于采用了智能指针作为容器,因此可以直接传递给`connect()`而无需担心生命周期问题[^1]。 ```cpp int main(int argc, char *argv[]) { QApplication app(argc, argv); auto emitterPtr = QSharedPointer<SignalEmitter>::create(); auto receiverPtr = QSharedPointer<SlotReceiver>::create(); connect(emitterPtr.data(), &SignalEmitter::dataChanged, receiverPtr.data(), &SlotReceiver::onDataReceived); // Emitting a test signal. emit emitterPtr->dataChanged("Test Message"); return app.exec(); } ``` #### 注意事项 - **线程安全性**:如果信号槽跨越不同线程,则应考虑连接类型的选择(直接连接或队列连接)。对于跨线程通信,默认情况下会采用队列模式以确保线程安全[^2]。 - **参数兼容性**:当设置为排队方式时,所有传递的数据类型都需要被Qt元对象系统所识别和支持,这样才能保证数据能在事件循环外正确复制保存。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

luoyayun361

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

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

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

打赏作者

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

抵扣说明:

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

余额充值