Ý tưởng
Xuất phát từ thực tế nhiều biến con trỏ (pointer) có thể dùng chung 1 vùng nhớ, khi hủy 1 pointer bằng từ khóa delete trong C++, các pointer khác dùng chung vùng nhớ đó sẽ rơi vào trạng thái "trỏ đến hư vô" (NULL
). Nếu giải phóng vùng nhớ đó 1 lần nữa sẽ gây ra lỗi vì 1 vùng nhớ không thể được giải phóng 2 lần. Do đó, hoặc là phải rất cẩn thận khi giải phóng 1 pointer, hoặc 1 phương pháp đơn giản để tự động quản lý công việc này.
Reference Counting sử dụng 1 biến đếm số lượng pointer trỏ vào 1 vùng nhớ. Khi có các pointer cùng trỏ đến 1 vùng nhớ, hoặc 1 pointer không còn trỏ đến vùng nhớ đó nữa, biến này sẽ được cập nhật lại tương ứng. Vùng nhớ sẽ thực sự được giải phóng khi biến đếm có giá trị bằng 0, hay nói cách khác là không còn pointer nào trỏ đến nó.


Hiện thực Reference Counting
class ReferenceCounting { private: int m_counter; public: ReferenceCounting() : m_counter(0){} virtual ~ReferenceCounting(){} void Grab(){ m_counter++; } void Release() { m_counter--; if(m_counter == 0) delete (ReferenceCounting*)this; } };
Trong hiện thực của lớp có các thành phần với chức năng như sau:
- Biến
m_counter
: số lượng các pointer đang cùng trỏ vào vùng nhớ. - Hàm
Grab
: quản lý việc thêm 1 pointer khác trỏ vào vùng nhớ. - Hàm
Release
: giải phóng vùng nhớ khi không còn pointer nào trỏ đến.
Sử dụng Reference Counting
Ở khai báo lớp, cho lớp kế thừa từ ReferenceCounting
để kích hoạt khả năng quản lý vùng nhớ của ReferenceCounting
.
Với mỗi trường hợp 1 pointer cần trỏ đến 1 biến cùng kiểu đã được khởi tạo, gọi hàm Grab
để tăng giá trị của biến đếm.
Khi 1 pointer hết giá trị sử dụng, gọi hàm Release
để kiểm tra và giải phóng vùng nhớ của pointer đó.
Ví dụ, sử dụng trong Project Sins (STDIO):
#include <stdio.h> class ReferenceCounting { private: int m_counter; public: ReferenceCounting() : m_counter(0){} virtual ~ReferenceCounting(){} void Grab(){ m_counter++; } void Release() { m_counter--; if(m_counter == 0) delete (ReferenceCounting*)this; } }; // Singleton template <class T> class Singleton { private: static T* s_instance; public: Singleton(){} virtual ~Singleton(){} static T* GetInstance() { { if(!s_instance) s_instance = new T(); return s_instance; } } }; template <class T> T* Singleton<T>::s_instance = NULL; // Class derive from ReferenceCounting class StdioFacebookPlugin : public ReferenceCounting, public Singleton<StdioFacebookPlugin> { private: // Some necessary variables int m_loginState; int m_shareState; public: StdioFacebookPlugin(){} virtual ~StdioFacebookPlugin(){} // Some neccesary function int StdioShare(){ return 1; } int StdioLogin(){ return 1; } void SetLoginState(int _state){ m_loginState = _state; } int GetLoginState(){ return m_loginState; } void SetShareState(int _state){ m_shareState = _state; } int GetShareState(){ return m_shareState; } }; StdioFacebookPlugin * FacebookLogin() { // ... StdioFacebookPlugin* plugin = Singleton< StdioFacebookPlugin >::GetInstance(); plugin->Grab(); plugin->SetLoginState(plugin->StdioLogin()); // ... return plugin; } StdioFacebookPlugin * FacebookSharing() { // ... StdioFacebookPlugin* plugin = Singleton<StdioFacebookPlugin>::GetInstance(); plugin->Grab(); plugin->SetShareState(plugin->StdioShare()); // ... return plugin; } int main() { // ... StdioFacebookPlugin* login = FacebookLogin(); StdioFacebookPlugin* share = NULL; if(login) { share = FacebookSharing(); } else { printf("Can't login.\n"); } // ... login->Release(); if(share) share->Release(); return 0; }