日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Qt 之 智能指针汇总

發布時間:2024/3/26 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Qt 之 智能指针汇总 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

來源
還有其他一些,做了一些匯總和測試,就不全列了。

文章目錄:
一、垂懸指針的問題
二、Qt中的智能指針
???? ??1、QPointer
???? ??2、QSharedPointer & QWeakPointer
???? ??3、QScopedPointer
???? ??4、其他智能指針
三、實踐記錄
四、用法舉例
???? ??1、QWeakPointer舉例
???? ??2、QScopedPointer 與 std::unique_ptr 舉例
???? ??3、測試樣例

代碼中出現一個bug,最終發現是由于在某個特殊情況下出現了使用垂懸指針,造成了程序崩潰,進而學習了解了Qt的智能指針機制。

一、懸垂指針的問題

如圖,有兩個指針a和b指向同一片內存,如果刪除其中一個指針a,再去使用指針b的話,程序會崩潰。因為指針b此時已經是一個垂懸指針(Dangling pointer)了,它指向的內存已經被釋放不再有效。

垂懸指針使用指針b之前先判斷b是否為空,這個做法在這里是不起作用的。問題的本質是通過指針a去釋放內存時,指針b沒有同步地置為空。
假如指針b能隨內存的釋放而自動置為空就好了,這正是智能指針所要解決的問題。

二、Qt中的智能指針

Qt提供了若干種智能指針:QPointer、QSharedPointer、QWeakPointer、QScopedPointer、QScopedArrayPointer、QSharedDataPointer、QExplicitlySharedDataPointer。
注:1、筆者Qt版本為4.8; 2、下述示例代碼中"Plot"為"QObject"類的子類。

1、QPointer

QPointer只用于QObject的實例。如果它指向的對象被銷毀,它將自動置空。
如圖:

QPointer這是Qt體系下的專門用于QObject的智能指針。常見使用方法:

QPointer<Plot> a(new T()); //構造 QPointer<Plot> a(b); //構造 a.isNull(); //判空 a.data(); //返回裸指針

2、QSharedPointer & QWeakPointer

QSharedPointer是引用計數(強)指針,當所有強指針銷毀時,實際對象才會銷毀。QWeakPointer是弱指針,可以持有對QSharedPointer的弱引用。它作為一個觀察者,不會引起實際對象銷毀,當對象銷毀時會自動置空。
這兩種指針同時都有以下3個成員:強引用計數strongRef,弱引用計數weakRef和數據data。
Qt引用計數指針



QWeakPointer兩種指針分別對應于C++中的std::shared_ptr和std::weak_ptr。常見使用方法://構造

QSharedPointer<Plot> a(new Plot()); QSharedPointer<Plot> b = a; QWeakPointer<Plot> c = a; //強指針構造弱指針 QWeakPointer<Plot> d(a);

//使用

c.clear(); //清除 a.isNull(); //判空 a->func(...); //(按常規指針來使用 "->") QSharedPointer<Plot> e = d.toStrongRef(); //弱指針轉為強指針。注意,弱指針無法操縱數據,必須轉為強指針 QWeakPointer<Plot> f = e.toWeakRef();//強指針顯式轉為弱指針 QSharedPointer<Plot> g = e.dynamicCast<T>(); //動態類型轉換

3、QScopedPointer

QScopedPointer保證當當前范圍消失時指向的對象將被刪除。它擁有一個很好的名字,它向代碼的閱讀者傳遞了明確的信息:這個智能指針只能在本作用域里使用,不希望被轉讓,因為它的拷貝構造和賦值操作都是私有的。相當于C++中的std::unique_ptr,實例代碼:

func(){Plot* plot = new Plot();//QScopedPointer出作用域自動銷毀內存QScopedPointer<Plot>qsp(plot);//plot沒有內存泄漏 }

4、其他智能指針

QScopedArrayPointer:一個QcopedPointer,默認刪除它指向Delete []運算符的對象。為方便起見,還提供了操作符[]。QSharedDataPointer/QExplicitySharedDataPointer搭配QSharedData類一起使用,以實現自定義隱式共享或顯式共享類。

三、實踐記錄

1、通常,要使用弱指針,必須將其轉換為強指針,因為這樣的操作確保了只要您使用它就會生存。這相當于“鎖定”訪問的對象,并且是使用弱指針指向的對象的唯一正確方法。并且轉換后使用前需要判空。

QSharedPointer<Plot> qsp = qwp.toStrongRef(); //qwp是QWeakPointer if(!qsp.isNull()){ qDebug() << qsp->getName(...); //使用指向的對象//... }

2、最好在new的時候就用QSharedPointer封裝,并管理起來。

QSharedPointer<Plot> qsp = QSharedPointer(new Plot());

3、使用智能指針包裝后,不要直接去刪除指針對象。

Plot* plot = new Plot(); QSharedPointer<Plot> qsp1(plot); delete plot; //運行時會提示:"shared QObject was deleted directly. The program is malformed and may crash."

4、不要多次使用同一裸指針構造QSharedPointer。Plot *plot = new Plot();

QSharedPointer<Plot> qsp(plot); QSharedPointer<Plot> qsp_ok = qsp; QSharedPointer<Plot> qsp_error(plot); //崩潰,輸出: “pointer 0x1f0a8f0 already has reference counting”

5、不要使用new直接構造QWeakPointer對象,它只能通過QSharedPointer的賦值來創建。QWeakPointer<Plot> a(new Plot()); //error: 引用計數:強-1 弱2
6、由于智能指針對象是值語義,參數傳遞時盡可能用const引用兼顧效率
7、關于動態轉換。使用QSharedPointer::dynamicCast()方法。
8、關于智能指針與QVariant轉換,并關聯到qobject的userdata。//注冊到元對象

Q_DECLARE_METATYPE(QWeakPointer<Plot>) //設置數據 item->setData(QVariant::fromValue(plot.toWeakRef()), Qt::UserRole); //取數據 QWeakPointer<Plot> plot = treeModel->data(index, Qt::UserRole).value<QWeakPointer<BasePlot> >();

9、關于Qt元對象系統自動析構和Qt智能指針自動析構相沖突的問題,經初步實驗Qt4.8中應該已經解決了?不過實際中,可以讓數據用智能指針管理,不用父子層級;窗體控件用父子層級,不用智能指針。

四、 用法舉例

1、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_OBJECTpublic: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;

這時候再次運行,就會看到輸出:

~Children ~Parent

這是因為在test()退出之前引用計數是1,函數退出之后就自動析構,這就解除了上面的循環引用。

2、QScopedPointer 與 std::unique_ptr

它們概念上應該是是一樣的。下面不再區分:

這是一個很類似auto_ptr的智能指針,它包裝了new操作符在堆上分配的動態對象,能夠保證動態創建的對象在任何時候都可以被正確地刪除。但它的所有權更加嚴格,不能轉讓,一旦獲取了對象的管理權,你就無法再從它那里取回來。

無論是QScopedPointer 還是 std::unique_ptr 都擁有一個很好的名字,它向代碼的閱讀者傳遞了明確的信息:這個智能指針只能在本作用域里使用,不希望被轉讓。因為它的拷貝構造和賦值操作都是私有的,這點我們可以對比QObject及其派生類的對象哈。

用法 (來自Qt的manual):

考慮沒有智能指針的情況,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;}

我們在異常處理語句中多次書寫delete語句,稍有不慎就會導致資源泄露。采用智能指針后,我們就可以將這些異常處理語句簡化了:

void myFunction(bool useSubClass){QScopedPointer<MyClass> p(useSubClass ? new MyClass() : new MySubClass);QScopedPointer<QIODevice> device(handsOverOwnership());if (m_value > 3)return;process(device);}

另,我們一開始的例子,也是使用這兩個指針的最佳場合了(出main函數作用域就將其指向的對象銷毀)。

注意:因為拷貝構造和賦值操作私有的,它也具有auto_ptr同樣的“缺陷”——不能用作容器的元素。

3、測試樣例

#include <QCoreApplication> #include <QSharedDataPointer> #include <QSharedPointer> #include <QWeakPointer> #include <QTimer> #include <QDebug> int main(int argc, char *argv[]) {QCoreApplication app(argc, argv);//raw pointer//QString *p = new QString("hello");QSharedPointer<QString> a(new QString("hello"));//QSharedPointer<QString> b = a;QWeakPointer<QString> c = a; //強指針構造弱指針QWeakPointer<QString> d(a);//使用a.clear();//c.clear(); //清除if(!c.toStrongRef().isNull()){qDebug() << c.isNull() << c.toStrongRef()->length();}else {qDebug() << "is null";}qDebug() << a.isNull(); //判空qDebug() << a->length()<<*(a.data()); //(按常規指針來使用 "->")QSharedPointer<QString> e = d.toStrongRef(); //弱指針轉為強指針。注意,弱指針無法操縱數據,必須轉為強指針QWeakPointer<QString> f = e.toWeakRef();//強指針顯式轉為弱指針QSharedPointer<QString> g = e.dynamicCast<QString>(); //動態類型轉換 // QScopedPointer<QString> t2(p); // QScopedPointer<QString> t3(p);// t3.reset(); // qDebug() << t3.data(); // qDebug() << *(t1.data()); // qDebug() << *(t2.take()->data());//Implements non-reference-counted strong pointer // QScopedPointer<QString> pScopedPointer(new QString("Scoped")); // // Build error, can NOT be shared and reference-counted // //QScopedPointer<QString> pScopedPointerpScopedPointer2 = pScopedPointer; // //Implements reference-counted strong sharing of pointers // QSharedPointer<QString> pSmart(new QString("Smart")); // QSharedPointer<QString> pSmart2; // pSmart2 = QSharedPointer<QString>(new QString("smart 2")); // QSharedPointer<QString> pSharedPoninter; // // can be shared safely and reference-counted // pSharedPoninter = pSmart; // qDebug() << *(pSmart.data()); // qDebug() << *(pSmart2.data()); // qDebug() << *(pSharedPoninter.data()); // qDebug() << pSharedPoninter.stro // QTimer *t = new QTimer; // QSharedPointer<QTimer> timer(t); // QWeakPointer<QTimer> pWeakPointer = timer; // pWeakPointer.data()->start(2000); // //Weak pointer's resources can be deleted from outside world // delete t; // qDebug() << timer.data(); // if (pWeakPointer.isNull()) // { // qDebug() << "contained QObject has been deleted"; // } }

總結

以上是生活随笔為你收集整理的Qt 之 智能指针汇总的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 九色综合网 | 欧美r级在线观看 | 永久免费看成人av的动态图 | 捆绑调教视频网站 | heyzo朝桐光一区二区 | a免费观看 | 色妻影院 | 亚洲不卡电影 | 成人片黄网站久久久免费 | 免费看欧美一级特黄a大片 国产免费的av | 欧美成人三级伦在线观看 | 亚洲最大黄色 | www.四虎在线观看 | 成人毛片av | 国产真实的和子乱拍在线观看 | 精品视频在线一区 | 最新超碰在线 | 丝瓜av| 好色999| 少妇脚交调教玩男人的视频 | 亚洲一级伦理 | 精品久久伊人 | 国产成人短视频在线观看 | 在线观看欧美 | 日韩成人一区二区视频 | 在线观看免费av网站 | 在线一区二区三区视频 | 狠狠一区 | 最好看的中文字幕国语电影mv | 亚洲成a人v欧美综合天堂麻豆 | 久久久看 | 成人在线视频观看 | 亚洲欧美日韩精品一区 | 91精品推荐 | 精品国产一级久久 | 欧美久久免费 | 欧美精品一区二区在线观看 | 日本人妻伦在线中文字幕 | 老司机精品视频在线播放 | 日韩 欧美 综合 | 国产乱国产乱老熟300部视频 | 日韩淫片| 高跟鞋和丝袜猛烈xxxxxx | 欧亚成人av| 亚洲一区二区三区人妻 | 久久免费国产精品 | 神马福利视频 | 黄色二级视频 | 天天摸日日摸 | 免费毛片小视频 | 欧美福利网 | 欧美日韩精品一区二区在线观看 | 午夜影院在线视频 | 成人精品亚洲人成在线 | 在线观看免费看片 | 成人av小说 | 国产suv精品一区二区883 | 少妇久久久久久被弄高潮 | 爱的色放3| 欧美一级在线视频 | 黄色三级在线视频 | 韩国美女视频在线观看18 | 91视频社区 | 在线视频日韩欧美 | 日韩欧美亚洲综合 | 综合久久91| 国产一区二区免费电影 | 一对一色视频聊天a | 亚洲免费av在线 | 91综合色| 欧美成人中文字幕 | 国产精品99久久久久 | 男女黄床上色视频 | 欧美另类视频在线观看 | 亚洲精品一区二 | 龚玥菲三级露全乳视频 | 日本在线国产 | 男男一级淫片免费播放 | 午夜精品一区 | 激情五月激情 | 欧美日本一区二区三区 | a毛片毛片av永久免费 | 老女人性生活视频 | 中文字幕1区2区3区 www.com黄色片 | 美足av| 国产91精品久久久久 | 9l视频自拍蝌蚪9l视频成人 | 久久鲁鲁 | 国产不卡视频在线播放 | 先锋影音av资源站 | 亚洲精品v天堂中文字幕 | 久久久久久久久久久久久久av | 黄色片hd| 五月婷婷激情综合 | 男女免费视频 | 亚洲国产97在线精品一区 | 91avcom| 国产在线一区视频 | 天天综合入口 |