當容器/數據結構需要釋放元素持有的資源,而資源獲取方式多樣(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 會導致未定義行為。
用戶提供含 operator() 的類,封裝具體釋放邏輯:
class MyReclaimRoutine {
public:
void operator()(LinkedListNode* p) {
delete p; // 或 free(p)、或 my_pool.release(p)
}
};
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_;
};
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 類型擦除存儲任意可調用對象// 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);
函數對象 + 模板 = 編譯期策略模式。適用於:
• 分配/釋放策略參數化
• 比較/哈希/排序謂詞參數化
• 回調/訪問者模式靜態化
• 任何需要「行為作為參數」且追求零開銷的場景