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

打造型別安全的 TList:從泛型封裝到自動釋放的完整實作

     編輯:VC 教學

TList 的先天缺陷

VCL TList 以 void* 儲存指標,Add(void*) 接受任何型別,編譯器零檢查。執行期取出時需手動 reinterpret_cast,一旦型別不符即導致未定義行為;且 TList 析構時不會自動 delete 內含物件指標,易造成記憶體洩漏。

解決方案:模板化封裝 TSafeList<T>

// SafeList.h
#ifndef SafeListH
#define SafeListH
#include <Classes.hpp>
#include <SysUtils.hpp>

template <class T>
class TSafeList : public TList
{
public:
    // 型別安全的加入
    int Add(T* Item) { return TList::Add(Item); }
    // 型別安全的插入
    void Insert(int Index, T* Item) { TList::Insert(Index, Item); }
    // 型別安全的存取
    T* Items[int Index] { return static_cast<T*>(TList::Items[Index]); }
    T* First() { return static_cast<T*>(TList::First()); }
    T* Last() { return static_cast<T*>(TList::Last()); }
    int IndexOf(T* Item) { return TList::IndexOf(Item); }
    // 移除並可選擇性 delete
    void Remove(T* Item, bool FreeItem = true) {
        int idx = IndexOf(Item);
        if (idx != -1) {
            if (FreeItem) delete Item;
            Delete(idx);
        }
    }
    // 自動釋放所有項目
    void ClearAndFree() {
        for (int i = 0; i < Count; ++i) delete Items[i];
        Clear();
    }
    // 析構時自動釋放(可選)
    __fastcall ~TSafeList() { ClearAndFree(); }
};
#endif

使用範例

#include "SafeList.h"
TSafeList<TButton>* BtnList = new TSafeList<TButton>;
BtnList->Add(new TButton(Form1));
BtnList->Add(new TButton(Form1));
// BtnList->Add(Application); // 編譯錯誤!型別不符
// 取出直接是 TButton*,無需 cast
TButton* btn = BtnList->Items[0];
btn->Caption = "Safe";
// 結束時
delete BtnList; // 自動釋放所有 TButton*

進階:支援非擁有權模式

若清單僅持有觀察者指標,不負責釋放,可加入擁有權旗標:

template <class T, bool OwnsItems = true>
class TSafeList : public TList { ... };
// 使用時
TSafeList<TButton, false> observerList; // 不 delete

為何不直接用 std::vector<std::unique_ptr<T>>?

  • VCL 專案常混用 C++Builder 標準庫與 STL,邊界轉換麻煩。
  • TList 整合 TComponent 擁有權機制(FreeNotification),TSafeList 可繼承此優勢。
  • 舊代碼遷移成本低:將 TList* 改為 TSafeList<T>* 即可,呼叫點幾乎不動。

總結

以 CRTP(奇異遞迴範本模式)或繼承 封裝 TList,在編譯期鎖定元素型別,於析構時自動釋放,兼顧型別安全與資源管理,是 VCL 專案中取代裸 TList 的最佳實踐。

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