Qt中的智能指针

Qt中的智能指针

Qt中提供了多种智能指针,用于管理自动分配的内存,避免内存泄漏和悬挂指针的问题。以下是Qt中常见的智能指针及其功能和使用场景:

1. QSharedPointer

QSharedPointer 是 Qt 框架中用于管理动态分配对象的智能指针,类似于 C++11 的 std::shared_ptr。它通过引用计数机制实现内存共享和自动释放.官方文档说明:QSharedPointer Class

功能

  • 多个 QSharedPointer 实例可以共享同一个对象。
  • 当最后一个 QSharedPointer 被销毁时,对象会被自动释放。
  • 支持自定义删除器,可用于管理数组或其他特殊资源
#include 
class MyClass {};
int main() {
    QSharedPointer ptr1(new MyClass());
    QSharedPointer ptr2 = ptr1; // ptr2 和 ptr1 共享同一个对象
    return 0;
}

注意事项

1.避免循环引用,可以使用 QWeakPointer 来解决。

2.引用计数机制会增加一定的性能开销。

2. QWeakPointer

QWeakPointer 是一个弱引用智能指针,用于解决 QSharedPointer 可能导致的循环引用问题。

  • 功能
    • 不增加引用计数,但可以安全地引用由 QSharedPointer 管理的对象。
    • 当所有 QSharedPointer 被销毁后,QWeakPointer 会自动置空。

检查对象是否仍然有效:

  • 通过 QWeakPointer::toStrongRef() 方法,检查指向的对象是否仍然有效,返回一个新的 QSharedPointer(如果对象仍然存在)或者一个空指针。
#include 
#include
#include
#include
#include
#include

class A
{
public:
    A(int nA,QString strName)
        :m_nA(nA),m_strName(strName)
    {
        qDebug() << m_strName << "调用 A 构造函数";
    }
    ~A()
    {
        qDebug() << m_strName << "调用 A 析构函数";
    }
    int m_nA;
    QString m_strName;
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // Set up code that uses the Qt event loop here.
    // Call a.quit() or a.exit() to quit the application.
    // A not very useful example would be including
    // #include 
    // near the top of the file and calling
    // QTimer::singleShot(5000, &a, &QCoreApplication::quit);
    // which quits the application after 5 seconds.

    // If you do not need a running Qt event loop, remove the call
    // to a.exec() or use the Non-Qt Plain C++ Application template.
    QSharedPointer ptr1(new A(10,"ptr1"));
    qDebug() << "ptr1中的值 = " << ptr1.get()->m_nA;
    QWeakPointer weakPtr1 = ptr1;

    if(auto ptr3 = weakPtr1.toStrongRef())
    {
        qDebug() << "Object is still alive.";
    }
    else
    {
        qDebug() << "Object is already destroyed.";
    }

    ptr1.clear();

    if(auto ptr4 = weakPtr1.toStrongRef())
    {
        qDebug() << "Object is still alive.";
    }
    else
    {
        qDebug() << "Object is already destroyed.";
    }

    {
        // 创建一个 QScopedPointer 指向 A对象
       QScopedPointer ptr5(new A(20,"ptr5"));

        // 使用 ptr5 时
        qDebug() << "Inside the scope";

    } // 离开作用域时 ptr5 会自动释放 A 对象

    {
        // 创建一个 QScopedPointer 指向 A对象
        QScopedPointer ptr6(new A(30,"ptr6"));
        // 错误:不能复制 QScopedPointer
        // QScopedPointer ptr7 = ptr6;


        QScopedPointer ptr7(new A(0,"ptr7"));
        ptr7.reset(ptr6.take());
        qDebug() << "ptr7中的值 = " << ptr7.get()->m_nA;


    } // 离开作用域时 ptr7 会自动释放 A 对象




    return a.exec();
}

上述代码运行结果:

A 构造函数
ptr1中的值 =  10
Object is still alive.
A 析构函数
Object is already destroyed.

总结:

  • QWeakPointer 是一个轻量级的引用,允许你从 QSharedPointer 中引用对象而不增加引用计数。
  • 使用 QWeakPointer 可以有效避免循环引用问题,同时可以安全地检查对象是否已经被销毁。

3. QScopedPointer

QScopedPointer 是一个自动管理内存的智能指针,它用于在作用域结束时自动删除其所管理的对象。QScopedPointer 是一种简单的自动化内存管理方式,适合用于在某个局部作用域内创建和销毁对象的情况。它类似于标准C++中的 std::unique_ptr,在作用域结束时自动释放资源,防止内存泄漏。

3.1 QScopedPointer 的特点:

  1. 作用域管理QScopedPointer 在离开作用域时会自动销毁它管理的对象,避免内存泄漏。
  2. 不可共享QScopedPointer 不能复制,只能转移所有权,因此适合在一个作用域中管理资源。
  3. 析构自动释放:当 QScopedPointer 被销毁时,它会自动调用所管理对象的析构函数,释放资源。

3.2 基本用法

 {
        // 创建一个 QScopedPointer 指向 A对象
       QScopedPointer ptr5(new A(20));

        // 使用 ptr5 时
        qDebug() << "Inside the scope";

 } // 离开作用域时 ptr5 会自动释放 A 对象

代码运行结果:

A 构造函数
Inside the scope
A 析构函数

3.3 使用 QScopedPointer 进行对象管理

QScopedPointer 是用于确保一个对象在离开作用域时自动释放的工具。它通常适用于单一所有权管理的情况。比如,下面的代码展示了在函数内部创建和自动销毁对象:

3.4 不能复制,能移动

QScopedPointer 不允许复制,因为复制会导致多个指针共享同一个对象,从而带来资源管理问题。它只支持转移所有权,即通过 reset() 或通过初始化一个新的 QScopedPointer 进行所有权的转移。

{
        // 创建一个 QScopedPointer 指向 A对象
        QScopedPointer ptr6(new A(30,"ptr6"));
        // 错误:不能复制 QScopedPointer
        // QScopedPointer ptr7 = ptr6;


        QScopedPointer ptr7(new A(0,"ptr7"));
        ptr7.reset(ptr6.take());
        qDebug() << "ptr7中的值 = " << ptr7.get()->m_nA;

    } // 离开作用域时 ptr7 会自动释放 A 对象

代码输出:

"ptr6" 调用 A 构造函数
"ptr7" 调用 A 构造函数
"ptr7" 调用 A 析构函数
ptr7中的值 =  30
"ptr6" 调用 A 析构函数

3.5reset()take() 方法

  • reset():重置 QScopedPointer,并释放其当前所管理的对象。如果指针为空,则不会执行任何操作。
  • take():从 QScopedPointer 中“取走”对象,转移所有权,返回原对象指针,并将 QScopedPointer 置为空。
QScopedPointer ptr1(new MyClass());
    
    // 使用 reset() 重置 ptr1
ptr1.reset(new MyClass());  // 释放原来的对象,创建一个新对象
    
    // 使用 take() 转移所有权
QScopedPointer ptr2(ptr1.take());  // ptr2 现在持有 MyClass 对象

4. QPointer

QPointer 是一个安全指针,专用于 QObject 及其派生类。

  • 功能
    • 当指向的 QObject 对象被销毁时,QPointer 会自动置空。
    • 避免悬挂指针问题。
#include 
#include 
QLabel *label = new QLabel("Hello, QPointer!");
QPointer pLabel(label);
delete label; // pLabel 会自动置空

5. QScopedArrayPointer

QScopedArrayPointer 是一个用于管理动态分配数组的智能指针。

功能

当超出作用域时,会自动使用 delete[] 释放数组。

不支持复制操作。

#include 
void example() {
    QScopedArrayPointer intArray(new int[10]);
    for (int i = 0; i < 10; ++i) {
        intArray[i] = i * 2;
    }
}

Qt提供了多种智能指针,每种指针都有其特定的用途和优势。根据实际需求选择合适的智能指针可以有效管理内存,避免内存泄漏和悬挂指针问题。

你可能感兴趣的:(Qt基础,qt)