隱性資料的共享

huffscan發表於2017-09-25

Qt 中許多 C++ 類使用了隱式資料共享技術,來最大化資源利用率和最小化拷貝時的資源消耗。當作為引數傳遞時,具有隱式資料共享的類即安全又高效。在資料傳遞時,實際上只是傳遞了資料的指標(這一切都是隱含幫你完成的),而只有在函式發生需要寫入的情況時,資料才會被拷貝(也就是通常所說的寫時複製)。本章我們將介紹有關隱式資料共享的相關內容,以便為恰當地使用前面所介紹的容器夯實基礎。

具有資料共享能力的類包含了一個指向共享資料塊的指標。這個資料塊包含了資料本身以及資料的引用計數。當共享物件建立出來時,引用計數被設定為 1。當新的物件引用到共享資料時,引用計數增加;當物件引用不再引用資料時,引用計數減少。當引用計數變為 0 時,共享資料被刪除。

在我們操作共享資料時,實際有兩種拷貝物件的方法:我們通常稱其為深拷貝和淺拷貝。深拷貝意味著要重新構造一個全新的物件;淺拷貝則僅僅複製引用,也就是上面所說的那個指向共享資料塊的指標。深拷貝對記憶體和 CPU 資源都是很昂貴的;淺拷貝則非常快速,因為它僅僅是設定一個新的指標,然後將引用計數加 1。具有隱式資料共享的物件,其賦值運算子使用的是淺拷貝來實現的。

這種隱式資料共享的好處是,程式不需要擁有不必要的重複資料,減少資料拷貝的需求。重複資料的代價是降低記憶體使用率(因為記憶體儲存了更多重複的資料)。通過資料共享,物件可以更簡單地作為值來傳遞以及從函式中返回。

隱式資料共享是在底層自動完成的,程式人員無需關心。這也是“隱式”一詞的含義。從 Qt4 開始,即使在多執行緒程式中,隱式資料共享也是起作用的。在很多人看來,隱式資料共享和多執行緒是不相容的,這是由引用計數的實現方式決定的。但是,Qt 使用了原子性的引用計數來避免多執行緒環境下可能出現的執行順序打斷的行為。需要注意的是,原子引用計數並不能保證執行緒安全,還是需要恰當的鎖機制。這種觀點對所有類似的場合都是適用的。原子引用計數能夠保證的是,執行緒肯定操作自己的資料,執行緒自己的資料是安全的。總的來說,從 Qt4 開始,你可以放心使用隱式資料共享的類,即使在多執行緒環境下。

我們可以使用QSharedDataQSharedDataPointer類實現自己的隱式資料共享類。

當物件即將被修改,並且其引用計數大於 1 時,隱式資料共享自動將資料從共享塊中拿出。隱式共享類必須控制其內部資料,在任何修改其資料的函式中,將資料自動取出。

相關文章