大型專案開發 謹慎使用智慧型指標

2021-09-22 22:00:16 字數 1826 閱讀 4224

智慧型指標的使用太普遍了,它讓程式設計師擺脫了記憶體管理的惡夢,但實際上智慧型指標本身也可能引入另乙個惡夢。主要包括兩個問題點:

效能問題。因為需要引入一些變數(bookkeeping),甚至在多執行緒下的一些互斥操作,它所帶來的效能開銷往往比想像的要高。比如以智慧型指標作為函式引數以及返回值時。

物件釋放的時機不明確。比如std::auto_ptr,總讓人感覺不明不白。而有時一些迴圈引用,又會導致記憶體洩露。

所以即便有了智慧型指標,程式設計師還是要認真考慮使用它們的時機。

所有權(ownership)是乙個用來管理動態分配記憶體的記錄(bookkeeping)技術。動態分配記憶體的所有者需要負責在所分配記憶體不再需要時釋放它。共享所有權時,最後乙個owner負責清理。即使不是共享,也可以在**間傳遞ownership。

運用智慧型指標的核心是保持所有權(ownership)的明確、清晰。一般情況下是保證所有權的單一,無論是使用weakptr, scoped pointer都可以保持所有權的單一,這時所有權可以在不同的物件/**段轉移。另一種情況就是需要共享所有權,比較常用的引用指數智慧型指標,就是幫助完成共享所有權的。

概括起來三個要點:

1.區域性化

推薦保持單

一、固定的所有權。當所有權需要在不同**段間傳遞時,就要使用智慧型指標。

2.明確的清理時機

使用引用計數,和std::auto_ptr都會引發對釋放時機的疑問。有可能引入一些隱晦的bug。當需要共享所有權時,一定要先思考這個設計的必要性,以及記憶體釋放的時機是否明確、清晰。

3.最好的方式不要使用指標。可以使用引用來代替指標。見後面webkit的故事。

google coding style的約定

如果需要動態分配記憶體,盡量由分配的**來持有所有權。

如果另一段**需要訪問物件,先考慮傳遞物件拷貝,指標或者引用,而不是傳遞所有權。如果確有需要時,建議使用std::unique_ptr來顯示的傳遞所有權(使用std::move())。

除非有好的理由,否則不要共享所有權。比如為了避免複製。這時需要確定有明顯的效能收益,而且所持有的物件最好是唯讀的, 同時建議使用std::shared_ptr:

std:

:shared_ptrfoo>;

新**裡不要再使用scoped_ptr,更不要使用std::auto_ptr, 而是使用std::unique_ptr來代替。

webkit的故事

webkit文件記錄了他們使用引用計數指標的故事,詳情見:refptr basics。大意為:

早在2023年時為了解決記憶體洩露問題,開始使用基於引用計數的智慧型指標,但是它有效能問題,特別是當作函式引數和返回值傳遞時。後來使用c++11提供move語義(即轉移所有權的方式)來解決了這個問題。(另外shared_ptr const & 的形式也可以避免不必要的引用計數操作。)

而到了2023年,webkit的開發者發現氾濫的判空和有效性檢查,於是開始傾向於盡可能地使用引用(注意:不是引用計數指標), 而不是指標。

解決記憶體問題的最佳的途徑仍然是由程式設計師管理好物件的生命週期。使用智慧型指標也是有成本的,同時也會引入一些新問題,所以需要遵循一些約定來使用。google chromium/webkit都有相應用的定義:

另外明確約定乙個函式是否會返回空指標,特別是對於api來說,也會幫助使用者避免一些不必要的判空處理和一些隱晦的bug。

進一步學習:

unique_ptr使用簡介

reference counting smart pointers are for retards.

智慧型指標使用摘要

1.如果沒有拷貝 賦值等要求,優先選用scoped ptr 2.如果不需要放入容器中 放入容器中的元素型別必須是能拷貝的 優先選用scoped ptr 3.如果不需要自定義刪除器,優先選用scoped ptr 4.盡量不要用scoped array管理new出來的陣列,改用vector代替 5.只能...

C 智慧型指標使用

由於 c 語言沒有自動記憶體 機制,程式設計師每次 new 出來的記憶體都要手動 delete。程式設計師忘記 delete,流程太複雜,最終導致沒有 delete,異常導致程式過早退出,沒有執行 delete 的情況並不罕見。std auto ptr boost scoped ptr boost ...

boost 智慧型指標使用

1 scoped ptr 基本功能類似auto ptr。首先確保任何時候物件都能被正確的刪除。且 scoped ptr所有權不能轉讓,一旦獲取,無法從它那裡取回。scoped ptr 不能作為容器的元素,不允許不支援拷貝和賦值,因為拷貝和賦值函式是私有的。即,不存在 sp1 sp2 這樣的操作。sc...