Spear Parser 是 Collins Model 1 解析模型的開源實作,包含訓練與解碼完整流程,適合作為自然語言處理統計解析的入門代碼庫。本系列將從底層輔助類別切入,第一篇剖析其智慧指標實作:RCObject(引用計數基類)與 RCIPtr(智慧指標模板)。
C++ 裸指標易造成記憶體洩漏、懸空指標、重複釋放等問題。智慧指標透過 RAII(資源獲取即初始化)自動管理物件生命週期,核心機制為引用計數:
delete 物件。class RCObject {
public:
void addReference(); // 計數 +1
void removeReference(); // 計數 -1,歸零時 delete this
protected:
RCObject(); // 預設建構
RCObject(const RCObject& rhs); // 複製建構(不複製計數)
RCObject& operator=(const RCObject&); // 指派(不複製計數)
virtual ~RCObject() = 0; // 純虛析構,強制繼承者實作
public:
unsigned short refCount; // 公開計數器(供 RCIPtr 直接存取)
};
inline RCObject::RCObject() : refCount(0) {}
inline RCObject::RCObject(const RCObject&) : refCount(0) {}
inline RCObject& RCObject::operator=(const RCObject&) { return *this; }
inline RCObject::~RCObject() {}
inline void RCObject::addReference() { ++refCount; }
inline void RCObject::removeReference() { if (--refCount == 0) delete this; }
refCount:讓 RCIPtr 直接操作,省去友元聲明,簡化模板實作。removeReference 中 delete this:物件自我銷毀,要求物件必須以 new 建立於堆疊。template <class T>
class RCIPtr {
public:
explicit RCIPtr(T* realPtr = 0);
RCIPtr(const RCIPtr& rhs);
~RCIPtr();
RCIPtr& operator=(const RCIPtr& rhs);
T* operator->() const;
T& operator*() const;
void clear() { *this = RCIPtr<T>(0); }
private:
T* pointee;
void init() { if (pointee != 0) pointee->addReference(); }
};
template <class T>
RCIPtr<T>::RCIPtr(T* realPtr) : pointee(realPtr) { init(); }
template <class T>
RCIPtr<T>::RCIPtr(const RCIPtr& rhs) : pointee(rhs.pointee) { init(); }
template <class T>
RCIPtr<T>::~RCIPtr() { if (pointee != 0) pointee->removeReference(); }
template <class T>
RCIPtr<T>& RCIPtr<T>::operator=(const RCIPtr& rhs) {
if (pointee != rhs.pointee) {
if (pointee != 0) pointee->removeReference();
pointee = rhs.pointee;
init();
}
return *this;
}
operator->()、operator*():透明轉發給內部裸指標,使用體驗與原生指標一致。clear():歸零指標,釋放原物件引用。class BankEdge : public RCObject { /* 業務邏輯 */ };
RCIPtr<BankEdge> head; // 相當於 BankEdge* head
head = new BankEdge(); // 計數 = 1
RCIPtr<BankEdge> another = head; // 計數 = 2
head->someMethod(); // 透明呼叫
head.clear(); // 計數 -1,another 仍持有
| 特性 | RCIPtr (Spear) | std::shared_ptr (C++11) |
|---|---|---|
| 引用計數位置 | 物件內部 | 控制區塊(分離) |
| 支援非繼承類別 | 否(須繼承 RCObject) | 是 |
| 執行緒安全 | 否 | 控制區塊原子操作 |
| 自定義刪除器 | 否 | 支援 |
| 循環引用處理 | 無 | 搭配 weak_ptr |
Spear 的實作極簡輕量,適合嵌入式或不想引入標準庫開銷的場景;現代專案建議優先使用 std::shared_ptr / std::unique_ptr。
RCObject + RCIPtr 展示了經典內建引用計數智慧指標的精髓:以極少代碼實現自動記憶體管理。理解其「計數歸零自我刪除」與「複製共享所有權」的語意,對掌握現代 C++ 智慧指標內部機制大有裨益。