精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

基于Qt 5.15源碼來聊聊隱式共享

嵌入式小生 ? 來源:嵌入式小生 ? 2023-02-12 16:52 ? 次閱讀

一、導讀

在實際開發中,Qt中很多類可以直接作為函數參數傳遞,這是為什么?其背后的實現機制又是什么?這些都歸功于隱式共享,本文基于Qt 5.15源碼,來聊聊隱式共享!

二、隱式共享簡介

Qt中的許多C++類使用隱式數據共享來提高資源使用并減少數據復制。當這些類作為參數傳遞時,因為只傳遞一個指向數據的指針,并且只有當函數寫入數據時數據才會被復制,即copy -on-write,隱式共享類是安全、高效的。

共享類由一個指向包含引用計數數據的共享數據塊的指針組成。

當創建共享對象時,它將引用計數設置為1。每當有新對象引用共享數據時,引用計數就遞增,當對象解引用共享數據時,引用計數就遞減,當引用計數變為零時,將刪除共享數據。

在處理共享對象時,有兩種方法復制對象。也就是經常談到的:深度拷貝淺拷貝。深度拷貝意味著復制一個對象,淺拷貝是一個引用拷貝,也就是一個指向共享數據塊的指針。站在內存和CPU角度,執行一個深度拷貝可能是昂貴的操作,執行淺拷貝則非常快,因為淺拷貝只涉及設置指針和增加引用計數。

注意:隱式共享對象的對象賦值(operator=())是使用淺拷貝實現的。

隱式共享的優點是:

(1)程序不需要進行不必要的數據復制操作,從而減少內存的使用和多次執行數據復制操作。

(2)可以很容易地被賦值。

(3)可以作為函數參數傳遞,并從函數中返回。

三、源碼角度分析隱式共享

隱式共享會自動將對象從共享塊中分離出來,如果對象即將改變并且引用計數大于1,(這通常被稱為寫時復制或值語義。)

隱式共享類可以控制其內部數據,在任何修改其數據的成員函數中,它都會在修改數據之前自動分離。(但是,需注意容器迭代器的特殊情況,后文將說明這一點!)

此處以QPen這個隱式共享類為例,從源碼角度分析QPen類是如何從更改內部數據的成員函數中分離共享數據的。在Qt5.15源碼中用于描述QPen的文件為qpen_p.h、qpen.cpp、qpen.h三個文件,位于源碼路徑(/qtbase/src/gui/painting目錄)下。在QPen類定義中有一個detach():

463b7818-aaae-11ed-bfe3-dac502259ad0.png

實現如下:

46767288-aaae-11ed-bfe3-dac502259ad0.png

detach()用于從共享pen數據中分離,以確保該pen只有一個引用數據,如果多個pen共享公共數據,這支pen將取消對數據的引用并獲得數據的副本;如果只有一個則返回,什么也不做。上述代碼中,QPenData實則是QPenPrivate的類型別名,用于描述QPen的數據,定義如下(位于qpen_p.h文件中):

46a27798-aaae-11ed-bfe3-dac502259ad0.png46bc3426-aaae-11ed-bfe3-dac502259ad0.png

上述代碼分析了detach()函數,下文以QPen的一個成員函數setStyle(Qt::PenStyle style)來描述,該函數實現如下:

4723201e-aaae-11ed-bfe3-dac502259ad0.png

從上述圖片所示,在setStyle()函數中,會使用detach()從公共數據中分離,然后在設置style成員。

綜上,如果Qt提供的類支持隱式共享,那么其源碼內部實現都有對應的數據管理機制,實現寫時復制。

四、隱式共享在開發中的使用

上述第二節描述了隱式共享的QPen類如何從更改內部數據的成員函數中分離共享數據。可簡化為下述代碼片段:

voidQPen::setStyle(Qt::PenStyles)
{
detach();//從公共數據中分離
d->style=s;//設置style成員
}

voidQPen::detach()
{
if(d->ref!=1){
...//執行深度拷貝
}
}

所以,在開發中如果更改了對象,類將自動與公共數據分離,甚至不會注意到這些對象是共享的。因此,可以將它們的單獨實例視為單獨的對象,它們始終作為獨立的對象。但在有些情況下可以共享數據,因此可以將這些類的實例作為參數按值傳遞給函數,而不必考慮復制開銷。

例如下列代碼:

QPixmapp1,p2;
p1.load("image.bmp");
p2=p1;//p1和p2共享數據

QPainterpaint;
paint.begin(&p2);//將p2從p1中分離出來
paint.drawText(0,50,"iriczhao");
paint.end();

注:在使用stl風格的迭代器時,復制隱式共享容器(QMap,QList等)需要特別注意。

五、隱式共享迭代器問題

對于stl風格的迭代器,在使用隱式共享類時應格外注意。因為當迭代器在容器上激活時,應該避免復制容器。也就是迭代器指向一個內部結構,如果復制一個容器,此時應特別注意迭代器。例如以下代碼片段:

QLista,b;
a.resize(100000);//創建一個大列表,里面填滿0。

QList::iteratori=a.begin();

/*-------------------------------------------------------------*/

//使用迭代器i的錯誤方法:
b=a;
/*
此時我們應該注意迭代器i,因為它將指向共享數據
如果我們執行*i=4,那么我們將改變共享實例(兩個向量)
其行為不同于STL容器。在Qt中不能這樣做。
*/

/*-------------------------------------------------------------*/

a[0]=5;
/*
容器a現在與共享數據分離,
盡管i是容器a的迭代器,但是它現在作為容器b的迭代器工作。
這里的情況是(*i)==0。
*/

b.clear();//現在迭代器i完全無效了。

intj=*i;//此時會出現未定義的行為!
/*
來自b(i所指向的)的數據不見了。
這可以用STL容器(和(*i)==5)定義,
但是這時候使用QList,可能會崩潰。
*/

總而言之:當迭代器在容器上激活時,應該避免復制容器,所有的Qt容器類都應該注意這一點。

六、隱式共享類和線程

在Qt中,對它的許多值類使用了隱式共享進行了優化,尤其是QImage和QString。從Qt 4開始,隱式共享類可以安全地跨線程復制。這些值類是完全可重入的。

一般情況下,都認為隱式共享和多線程是不兼容的概念,因為引用計數通常不允許這樣做。然而,Qt使用原子引用計數來確保共享數據的完整性,避免了引用計數器的潛在損壞。

但是需要注意原子引用計數不能保證線程安全性。在線程之間共享隱式共享類的實例時,應該適當的加鎖進行鎖定。這一點,與所有重入類(無論是否共享)相同。原子引用計數確實保證了一個線程在其自身、隱式共享類的本地實例上工作是安全的,所以,在開發中可以使用信號和槽函數機制在不同線程之間傳遞數據,因為這可以在不需要顯式鎖定的情況下完成。

總而言之,Qt 中的隱式共享類實際上是隱式共享的。即使在多線程應用程序中,也可以安全地使用它們,與普通的、非共享的、可重入的基于值的類一樣。






審核編輯:劉清

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • cpu
    cpu
    +關注

    關注

    68

    文章

    10825

    瀏覽量

    211140
  • C++語言
    +關注

    關注

    0

    文章

    147

    瀏覽量

    6970
  • 迭代器
    +關注

    關注

    0

    文章

    43

    瀏覽量

    4302

原文標題:懂Qt,隱式共享都知道嗎?

文章出處:【微信號:嵌入式小生,微信公眾號:嵌入式小生】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    共享三年嵌入項目資料(源碼+實物圖+原創)(申精帖)!

    . 醫學圖像系統(只支持大部分的CT,DR,CR)十二STM32F103VBT6超屏解決OV7660高速數據同步讀取十三.DIY的wav播放器(有圖有源碼)十四. DIY的STM32驅動OV7660
    發表于 04-13 15:25

    手動編譯QT源碼生成qmake

    交叉編譯QT4.8.7源碼生成qmake工具TQ-i.MX6UL使用的QT版本是QT4.8.7,板卡出廠前附帶的開發資料中,天嵌官方沒有為開發者編譯生成qmake工具。因此,為了后續進
    發表于 11-05 08:20

    qt源碼庫在樹莓派中的部署方法

    接安裝qt。本文介紹最普遍的部署方式,就是在pc端的ubuntu中交叉編譯庫源碼,然后上傳編譯好的庫到樹莓派,最后配置qt creator交叉編譯的kit實現在pc端編譯自碼程序,上
    發表于 12-24 06:44

    請問QT怎么實現源碼編譯?

    你好,QT怎么實現源碼編譯,
    發表于 12-31 07:49

    qt源碼編譯安裝遇到的問題

    QT源碼make通過后執行make install時報錯。
    發表于 12-09 15:56

    推薦使用QT5.14或者QT5.15版本 不要急著升級到QT6

    ? 推薦使用QT5.14或者QT5.15版本,不建議升級最新版的QT6,很多你要的功能沒了,特別是開發上位機需要的模塊沒了。 Qt 6.0 中已移除的模塊,以下是不在
    的頭像 發表于 01-26 16:37 ?4.8w次閱讀

    嵌入Linux的QT版本,嵌入Linux版本Qt5.4快速部署

    關鍵詞:摘要:Qt是一個領先的跨平臺應用和UI 開發框架(Framework),使用標準C++,適用于桌面,嵌入和移動平臺。本文著重就利用Boot to Qt軟件包實現
    發表于 11-01 17:20 ?0次下載
    嵌入<b class='flag-5'>式</b>Linux的<b class='flag-5'>QT</b>版本,嵌入<b class='flag-5'>式</b>Linux版本<b class='flag-5'>Qt</b>5.4快速部署

    嵌入linux安裝qt,嵌入Linux版本Qt5.4快速部署

    摘要:Qt是一個領先的跨平臺應用和UI 開發框架(Framework),使用標準C++,適用于桌面,嵌入和移動平臺。本文著重就利用Boot to Qt 軟件包實現
    發表于 11-02 10:51 ?0次下載
    嵌入<b class='flag-5'>式</b>linux安裝<b class='flag-5'>qt</b>,嵌入<b class='flag-5'>式</b>Linux版本<b class='flag-5'>Qt</b>5.4快速部署

    嵌入Linux開發環境搭建-(6)交叉編譯QT4.8.7源碼生成qmake工具

    交叉編譯QT4.8.7源碼生成qmake工具TQ-i.MX6UL使用的QT版本是QT4.8.7,板卡出廠前附帶的開發資料中,天嵌官方沒有為開發者編譯生成qmake工具。因此,為了后續進
    發表于 11-02 13:21 ?3次下載
    嵌入<b class='flag-5'>式</b>Linux開發環境搭建-(6)交叉編譯<b class='flag-5'>QT</b>4.8.7<b class='flag-5'>源碼</b>生成qmake工具

    怪獸充電寶 共享充電寶源碼

    介紹:怪獸充電寶源碼共享充電寶源碼,怪獸充電是一款全新的智能共享充電寶產品,受到廣大用戶的喜愛,也便利了人們的生活。網盤下載地址:http://kekewl.cc/rdeOykY31r
    發表于 01-07 09:36 ?32次下載
    怪獸充電寶 <b class='flag-5'>共享</b>充電寶<b class='flag-5'>源碼</b>

    Qt ECG Monitor Qt嵌入床旁心電監護儀項目源碼

    Qt ECG Monitor是由Qt-UI開發和維護的嵌入床旁心電監護儀界面項目。項目提供C++/Python語言,基于Qt5下原生QWidget編譯開發,包含以下功能界面:包含Wi
    發表于 01-10 11:41 ?31次下載
    <b class='flag-5'>Qt</b> ECG Monitor <b class='flag-5'>Qt</b>嵌入<b class='flag-5'>式</b>床旁心電監護儀項目<b class='flag-5'>源碼</b>

    記錄整個Qt環境的搭建過程

    整個Qt環境安裝過程大約花了一個小時,完成后,在Windows的『開始』菜單中也可以找到對應的快捷方式。至此,Qt 5.15就安裝完成啦!
    的頭像 發表于 09-05 15:13 ?1332次閱讀

    QT設計的網絡助手源碼

    QT設計的網絡助手源碼
    發表于 09-27 11:46 ?2次下載

    qt設計的Google拼音輸入法源碼

    qt設計的Google拼音輸入法源碼分享
    發表于 09-26 17:40 ?1次下載

    qt opencv opencl opengl源碼例程

    qt-opencv-opencl-opengl-源碼例程
    發表于 09-27 14:42 ?1次下載