Qt的智能指針們——Qt

前言

用c++語言開發的一個難點就是指針,但是指針又是最常用的。有時候開闢了一塊內存,但是後續使用完忘記釋放,這就造成內存的泄露。爲了解決這種尷尬的情況,除了長點心:一個new對應一個delete;還有一個辦法是使用智能指針。

這裏我只稍微說下Qt的常用的智能指針們,和c++11的部分智能指針很像。如果對c++的智能指針很熟悉,這裏看一眼就沒問題了;若c++基礎不紮實,我找了篇c++11智能指針詳解,兩者可以結合着看。

 

介紹和示例

智能指針是個類,主要用於管理在堆上分配的內存,它將普通的指針封裝爲一個棧對象。

QPointer Qt的指針

QPointer所指向的對象必須是QObject或其派生類對象。 因爲其對象析構時會執行QObject的析構函數,進而執行QObjectPrivate::clearGuards(this);作用對象被銷燬時,自動設置爲NULL,這樣就不會出現野指針誤用的情況了。(注意:寫"."和"->"所調用的成員變量是不同的,一個是QPointer對象本身,一個是QPointer指向的指針對象。)

還有就是QPointer是線程不安全的,注意使用場合。

#include <QCoreApplication>
#include <QObject>
#include<QDebug>
#include<QPointer>
#include<QSharedPointer>
#include<QScopedPointer>

class Student:public QObject
{
public:
    explicit Student(QObject* parent=nullptr) :QObject(parent)
    {
        qDebug()<<__FUNCTION__;
    }
    ~Student()
    {
        qDebug()<<__FUNCTION__;
    }
};
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QPointer<Student> pt=new Student;
    delete pt;
    qDebug()<<"pt.isNull():"<<pt.isNull()<<"\n";

    Student* pt2=new Student;
    delete pt2;
    if(pt2)
    {
        qDebug()<<"pt2 is not null";

    }
    pt2=NULL;


    return a.exec();
}

執行結果如下,可以看出若用QPointer釋放後,指針直接爲空,而普通的指針釋放,則不是空,需手動置零。

 

QSharedPointer共享指針

與 C++中的std::shared_ptr其作用是一樣的,是引用計數型的智能指針。使用QSharedPointer時不需要再時刻牢記delete對象以避免內存泄漏, 因爲當QSharedPointer超出其作用域時將被銷燬;若對象的引用計數爲0時, 也將會銷燬其封裝或指向的對象。

還有一點:QSharedPointer 是線程安全的,因此即使有多個線程同時修改 QSharedPointer 對象也不需要加鎖。雖然 QSharedPointer 是線程安全的,但是 QSharedPointer 指向的內存區域可不一定是線程安全的。所以多個線程同時修改 QSharedPointer 指向的數據時還要應該考慮加鎖。

    QSharedPointer<Student> pt(new Student);
    QSharedPointer<Student> pt2=pt;

    qDebug()<<" pt.reset();";
    pt.reset();
    qDebug()<<"pt2.reset()";
    pt2.reset();

運行結果如下,可以看出當兩個共享指針都不再引用此對象時,被封裝的對象被自動釋放。

 

QScopedPointer作用域指針


QScopedPointer和C++中的智能指針std::unique_ptr其概念是一樣的,它包裝了new操作符在堆上分配的動態對象,能夠保證動態創建的對象在任何時候都可以被正確地刪除。

QScopedPointer擁有指針的管理權,出了作用域將自動釋放刪除。 注意這裏並不會檢查這個對象是否應該刪除, 或者是否有其他指針依然引用/指向這個對象, 而是直接刪除它.。這也是QScopedPointer和QSharedPointer在自動銷燬對象這一作用上的區別。

void test()
{
    QScopedPointer<Student> pt(new Student);
}
Student* takeData()
{
    QScopedPointer<Student> pt(new Student);
    qDebug()<<pt.data();
    return pt.take();
}

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

    //超出作用域,釋放
    test();

    //轉讓管理權
    QScopedPointer<Student> pt(takeData());
    qDebug()<<pt.data();
    pt->sayHello();


    return a.exec();
}

 運行結果如下,以下演示了超出作用域後的釋放,和轉移管理權的示例,注意QScopedPointer::data雖然將對象指針給出去了,但是管理權還在QScopedPointer身上。

 

數組QScopedArrayPointer

因爲QScopedPointer的拷貝構造和賦值操作私有的,所以不能用作容器的元素。所以就有了QScopedArrayPointer。這個用法很簡單不說了,麻煩。

 

結束語

c++基礎沒打好,現在看到一點知識,進行一點學習,加油吧,少年!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章