首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

RAII智能指針深度評析:為何沒有萬能替代品能取代裸指針

     編輯:關於C語言

前言:從排斥到深度剖析

早年習慣裸指針(Dumb Pointer),對auto_ptr等RAII類視而不見。直到頻繁在技術討論中見其身影,決心徹底研究。讀遍《Effective C++》、《More Effective C++》、《C++ Standard Library》、Boost/TR1源碼,發現:智能指針帶來的便利與陷阱同在,不存在完美替代品。

auto_ptr:殘缺的先驅

四大硬傷

  1. 不可共享所有權:複製即轉移所有權,雙auto_ptr管理同一裸指針→雙重delete崩潰。
  2. 不支援數組:析構執行delete而非delete[],管理new T[n]必漏內存。
  3. 不滿足STL容器值語義:複製後源對象變空,違背容器要求「複製後值相等」的契約,塞入vector即災難。
  4. 派生類轉基類受阻:auto_ptr<Derived>無法隱式轉auto_ptr<Base>,模板類型系統阻斷了裸指針天然的多態轉換。

典型踩坑代碼

// 錯誤1:雙重管理
BaseClass* p = new BaseClass;
auto_ptr<BaseClass> p1(p), p2(p); // 析構雙重delete

// 錯誤2:按值傳參導致所有權轉移
void foo(auto_ptr<int> p) { if(p.get()) cout << *p; }
auto_ptr<int> p(new int(100));
foo(p); *p = 10; // p已空,未定義行為

// 錯誤3:按引用傳參仍被竄改
void bar(auto_ptr<int>& p) { auto_ptr<int> p2 = p; } // p被偷走
// 唯一安全:const引用
void safe(const auto_ptr<int>& p); // 編譯器阻止所有權轉移

shared_ptr:引用計數的雙刃劍

核心機制

  • 構造計數=1,複製/賦值++count,析構--count==0時delete。
  • 線程安全計數(VC++用_InterlockedIncrement等內建指令)。
  • 支援自定義刪除器(函數對象),解決delete[]/跨DLL/檔案句柄等場景。

解決了auto_ptr的1、3、4號問題

  • 可共享所有權、可入STL容器、可按值/引用安全傳參。
  • 派生轉基類仍受模板類型限制(需自定義轉換構造)。

新敵人:循環引用

class A { shared_ptr<B> b; };
class B { shared_ptr<A> a; };
void leak() {
    auto a = make_shared<A>();
    auto b = make_shared<B>();
    a->b = b; b->a = a; // 計數永不歸零,內存洩漏
}

若改用auto_ptr會直接崩潰(轉移所有權導致空指針訪問),至少能在調試期發現;shared_ptr靜默洩漏更隱蔽。

weak_ptr:打破循環的觀察者

  • 不增加引用計數,不重載*/->,不可直接訪問對象。
  • 核心接口:lock()→嘗試提升為shared_ptr(失敗返回空)、expired()、use_count()。
  • 用法:將A::b或B::a改為weak_ptr即可斷環。

痛點:需要程序員預知循環點。大型項目中難以全覆蓋,洩漏常在壓測/線上才暴露。

線程安全的邊界

Boost文檔:shared_ptr「提供與內建類型同級線程安全」——僅計數操作原子化。多線程同時reset/賦值同一shared_ptr實例仍未定義行為;不同實例(即使共享計數)並發讀寫安全。別誤以為它解決了所有併發問題。

後記:工程選型的決策框架

「靈巧指針應謹慎使用,但每個C++程序員最終都會發現它們有用。」 —— Scott Meyers

場景推薦理由
單一所有權、無拷貝傳遞、非STL容器unique_ptr (C++11)零開銷、編譯期強制所有權語義
多方共享、需入容器、跨模塊生命週期shared_ptr引用計數自動管理,配合weak_ptr斷環
高性能熱路徑、確定性生命週期、團隊紀律強裸指針 + 文檔約定零開銷、零間接層、需代碼審查把關
管理動態數組unique_ptr<T[]> / boost::scoped_array正確調用delete[]

結語:沒有銀彈。理解每種工具的邊界成本,在「預知便利遠大於麻煩」時果斷使用,才是資深工程師的選擇。Reference Counting思想在Cocos2d-x等引擎中已極致應用,或許未來博文再展開。


本文出自「酋長」博客,轉載請保留出處。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved