Qt智能指針--QScopedPointer


概述

QScopedPointer和C++中的智能指針std::unique_ptr其概念是一樣的,它包裝了new操作符在堆上分配的動態對象,能夠保證動態創建的對象在任何時候都可以被正確地刪除。但它有更嚴格的所有權,並且不能轉讓,一旦獲取了對象的管理權,你就無法再從它那里取回來。也就是說,只要出了作用域,指針就會被自動刪除,因為它的拷貝構造和賦值操作都是私有的,與QObject及其派生類風格相同。

QScopedPointer

首先我們來看一個官方示例:

沒有使用智能指針:

void myFunction(bool useSubClass)
{
    MyClass *p = useSubClass ? new MyClass() : new MySubClass;
    QIODevice *device = handsOverOwnership();

    if (m_value > 3) {
        delete p;
        delete device;
        return;
    }

    try {
        process(device);
    }
    catch (...) {
        delete p;
        delete device;
        throw;
    }

    delete p;
    delete device;
}

上面的寫法,稍有不慎就會導致內存泄露,但是如果使用智能指針,就會變得很簡單了:

void myFunction(bool useSubClass)
 {
     QScopedPointer<MyClass> p(useSubClass ? new MyClass() : new MySubClass);
     QScopedPointer<QIODevice> device(handsOverOwnership());

     if (m_value > 3)
         return;

     process(device);
 }

注意:因為拷貝構造和賦值操作私有的,所以不能用作容器的元素。

const 限制

C ++指針的const限定也可以用QScopedPointer表示:

    const QWidget *const p = new QWidget();
    // 等同於:
    const QScopedPointer<const QWidget> p(new QWidget());

    QWidget *const p = new QWidget();
    // 等同於:
    const QScopedPointer<QWidget> p(new QWidget());

    const QWidget *p = new QWidget();
    // 等同於:
    QScopedPointer<const QWidget> p(new QWidget());

考慮一種情況

上面說到,使用QScopedPointer智能指針動態創建的對象,一旦出了作用域就會 被自動釋放並置空,那么如果需要函數返回值怎么辦呢?

比如下面這種情況:

QLabel * createLabel()
{
    QScopedPointer<QLabel> pLabel(new QLabel());
//    return pLabel.data();  //invalid
    return  pLabel.take(); //valid
}

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QScopedPointer<QLabel> p1(createLabel());
    p1->setText("hello");
    p1->show();

    return a.exec();
}

注意,我們在createLabel()函數中創建label對象並返回時,不能使用data(),而要使用take();
因為 T *QScopedPointer::data() const返回指向對象的常量指針,QScopedPointer仍擁有對象所有權。 所以通過data()返回過后就被自動刪除了,從而導致mian函數中的p1變成了野指針,程序崩潰。
而使用T *QScopedPointer::take()也是返回對象指針,但QScopedPointer不再擁有對象所有權,而是轉移到調用這個函數的caller,同時QScopePointer對象指針置為NULL。
另外還有一個函數要注意。
void QScopedPointer::reset(T *other = Q_NULLPTR):delete目前指向的對象,調用其析構函數,將指針指向另一個對象other,所有權轉移到other。

QScopedArrayPointer

對應的還有一個指針QScopedArrayPointer,專門用於處理數組,其用法和QScopedPointer是一樣的

官方簡單示例:

void foo()
  {
      QScopedArrayPointer<int> i(new int[10]);
      i[2] = 42;
      ...
      return; // our integer array is now deleted using delete[]
  }

超出作用域過后會自動調用delete[]刪除指針,這里就不展開描述了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM