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
TList 整合 TComponent 擁有權機制(FreeNotification),TSafeList 可繼承此優勢。TList* 改為 TSafeList<T>* 即可,呼叫點幾乎不動。以 CRTP(奇異遞迴範本模式)或繼承 封裝 TList,在編譯期鎖定元素型別,於析構時自動釋放,兼顧型別安全與資源管理,是 VCL 專案中取代裸 TList 的最佳實踐。