在 C++ 中管理動態記憶體的生命週期向來是棘手問題。傳統的「誰分配誰釋放」原則在複雜的物件共享場景下極易導致記憶體洩漏或重複釋放。參考計數透過記錄物件被引用的次數,當計數歸零時自動釋放資源,完美解決了共享擁有權的難題,也是現代智慧指標(如 std::shared_ptr)的核心基石。
RCObject 封裝了參考計數的基本邏輯:
refCount:當前引用計數。shareable:標記物件是否可共享(支援 Copy-on-Write)。AddReference() / RemoveReference():增減計數,歸零時 delete this 自毀。markUnshareable() / isShareable() / isShared():輔助 Copy-on-Write 判斷。關鍵設計點:
refCount 初始化為 0,避免新建物件被誤判為已共享。RCPtr 模板類模擬指標行為,自動管理 RCObject 衍生物件的生命週期:
init() 增加計數。RemoveReference() 減少計數。init() 內實現 Copy-on-Write:若物件不可共享(!isShareable()),則深度複製一份新物件並標記為不可共享,確保寫入操作不影響其他共享者。範例展示如何利用 RCPtr 實作高效字串類:
StringValue 繼承 RCObject,持有 char* data。operator[] 直接回傳引用;寫入版 operator[] 檢測 isShared(),若被共享則觸發深度複製(new StringValue(*value))並標記不可共享,實現寫時複製優化。class RCObject { /* ... 參考計數核心邏輯 ... */ };
template <class T> class RCPtr { /* ... 智慧指標封裝 ... */ };
class String {
struct StringValue : public RCObject {
char* data;
StringValue(const char* initValue) { /* 配置記憶體並複製 */ }
StringValue(const StringValue& rhs) { /* 深度複製 */ }
~StringValue() { delete[] data; }
void init(const char* initValue) { /* 通用初始化 */ }
};
RCPtr<StringValue> value;
public:
String(const char* value = "") : value(new StringValue(value)) {}
const char& operator[](int index) const { return value->data[index]; }
char& operator[](int index) {
if (value->isShared()) value = new StringValue(value->data);
value->markUnshareable();
return value->data[index];
}
};
優點:手動實作極具教學意義,展示參考計數、Copy-on-Write、RAII 核心思想。
缺點:非執行緒安全(refCount 非原子操作)、缺乏弱引用支援、循環引用無法釋放。
現代 C++ 建議直接使用 std::shared_ptr/std::weak_ptr(C++11 起),其內部採用原子計數與控制區塊設計,解決上述問題。
參考計數是資源管理的經典模式。透過 RCObject + RCPtr 的組合,我們得以在 C++98 時代構建出類似 Java 參考語義的智慧指標,深入理解其運作機制對掌握現代 C++ 智慧指標原理大有裨益。