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

C++ 函數對象實戰:解決資源釋放策略多態的最佳模式

     編輯:關於C++

當容器/數據結構需要釋放元素持有的資源,而資源獲取方式多樣(new/malloc/自定義分配器)時,析構邏輯無法硬編碼。函數對象(仿函數)通過模板參數化釋放策略,實現編譯期多態,零開銷解決此問題。

問題場景

class LinkedListNode {
    int data_;
    LinkedListNode* next_;
};

class LinkedList {
public:
    void insert(LinkedListNode*& p); // 外部分配節點內存
    void del(LinkedListNode* p);     // 如何釋放 p 的內存?
private:
    LinkedListNode* head_;
};

// 用戶代碼
LinkedList list;
LinkedListNode* p = new LinkedListNode(2, nullptr); // new 分配
// 或 malloc、或自定義池分配
list.insert(p);
// ...
list.del(p); // 這裡該 delete 還是 free?

困境:del 內部無法知道 p 來自 new、malloc 還是其他分配器。硬編碼 delete 會導致未定義行為。

解決方案:模板化回調策略

1. 定義函數對象接口

用戶提供含 operator() 的類,封裝具體釋放邏輯:

class MyReclaimRoutine {
public:
    void operator()(LinkedListNode* p) {
        delete p;           // 或 free(p)、或 my_pool.release(p)
    }
};

2. 容器模板接受策略類型

template <typename CallBack>
class LinkedList {
public:
    void insert(LinkedListNode*& p);
    void del(LinkedListNode* p) {
        // ... 解鏈邏輯 ...
        LinkedListNode* prev = get_prev(p);
        prev->next_ = p->next_;
        
        CallBack cb;           // 默認構造策略對象
        cb(p);                 // 調用用戶釋放邏輯
    }
private:
    LinkedListNode* head_;
};

3. 用戶端代碼:類型安全、零開銷

LinkedList<MyReclaimRoutine> list; // 編譯期綁定策略
LinkedListNode* p = new LinkedListNode(2, nullptr);
list.insert(p);
list.del(p); // 自動調用 MyReclaimRoutine::operator() → delete p

核心優勢

方案靈活性性能類型安全代碼膨脹
虛函數回調高虛調用開銷運行期無
函數指針中間接調用無無
函數對象模板高內聯優化,零開銷編譯期輕微(每種策略一份代碼)

擴展:支持有狀態的釋放器

class PoolReclaimer {
    MemoryPool& pool_;
public:
    explicit PoolReclaimer(MemoryPool& pool) : pool_(pool) {}
    void operator()(LinkedListNode* p) { pool_.deallocate(p); }
};

// 使用
MemoryPool pool;
LinkedList<PoolReclaimer> list(PoolReclaimer(pool)); // 需構造函數傳遞狀態
// 或 C++17 類模板參數推導 (CTAD) + 指引

標準庫中的應用

  • std::unique_ptr<T, Deleter>:第二模板參數為刪除器類型
  • std::shared_ptr 構造函數接受刪除器
  • std::function 類型擦除存儲任意可調用對象
  • STL 算法接受一元/二元謂詞(函數對象/lambda)

現代 C++ 寫法(C++11/14/17)

// Lambda 作為策略(需模板化存儲類型,或用 std::function)
template <typename Deleter = std::default_delete<LinkedListNode>>
class LinkedList {
    Deleter deleter_;
public:
    explicit LinkedList(Deleter d = Deleter()) : deleter_(std::move(d)) {}
    void del(LinkedListNode* p) {
        // ...
        deleter_(p); // 支持 lambda、函數對象、函數指針
    }
};

// 使用
auto deleter = [](LinkedListNode* p) { my_pool.release(p); };
LinkedList<decltype(deleter)> list(deleter);

總結

函數對象 + 模板 = 編譯期策略模式。適用於:
• 分配/釋放策略參數化
• 比較/哈希/排序謂詞參數化
• 回調/訪問者模式靜態化
• 任何需要「行為作為參數」且追求零開銷的場景

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