TList对象的缺点与改进

C++ Builder中,VCL库包含一个TList类,用于管理指针列表。然而,TList类含有许多缺点,其中最严重的缺点是TList缺乏类型的安全性及内存空间的自动释放。本文将探讨TList类的缺点,并提出改进方法。

一、TList的问题

1TList主要用来存储对象的指针,使用方便,但是这个类的主要缺点是缺乏安全性,因为它存储并维护的是空指针(void *),让我们看看它的Add方法的原型:

int __fastcall Add(void * Item);

C++编译器能正确地将任何类型的指针转换为void *型指针,因此,TListAdd方法能接受你传给它的任何一个指针。这其中就产出了一个问题,当你想维护TList中的对象指针列表时,你能肯定TList中的指针具有相同类型吗?例如:

TList *ButtonList = new TList;          // create a list of buttons

 

 ButtonList->Add(Button1);             // add some buttons to the list

 ButtonList->Add(Button2);             //

 ButtonList->Add( new TButton(this));   // OK so far

 ButtonList->Add(Application);          // Application is not a button

 ButtonList->Add(Form1);              // neither is Form1

 ButtonList->Add((void *)534);   

 ButtonList->Add(Screen);

以上代码能正确编译通过,从中我们能看出,TList能处理任何对象,它在接受任何一个对象时不做任何类型检查。当你要引用TList中的一个对象时,由于它是一个空指针,你必须将它转换为一个正确类型的指针,具体方法如下:

TList *ButtonList = new TList;   

ButtonList->Add(Button1);

 … …            // 生成一个对象指针列表

TButton *button = reinterpret_cast<TButton *>(ButtonList->Items[1]);

//引用对象

button->Caption = "I hope it's really a button";   

delete ButtonList;

在以上代码中,TListItem数组返回一个空指针(void *),要引用其中的一个TButton型的指针,必须将其转换为TButton型,这种转换的前提条件是你能肯定TListItem返回的指针原来指向一个TButton对象。也许有个认为用dynamic_cast 操作符来完成这种转换,然而不幸的是由于空指针不含有任何类型信息,上述缺点仍然无法消除。

2TList的另一个缺点是它不能自动删除其列表中的指针,要完全删除列表,必须遍历整个列表,将列表中的指针一个个删除。例如:

  TList *ButtonList = new TList;          // 生成一个对象列表

    ButtonList->Add(new TButton(Handle));   // 向列表中添加TButton对象

    ButtonList->Add(new TButton(Handle));

    ButtonList->Add(new TButton(Handle));

ButtonList->Add(new TButton(Handle));   

int nCount = ButtonList->Count;    //引用列表中对象的个数

for (int j=0; j<nCount; j++)

        delete ButtonList->Items[j];    // 删除指针

  delete ButtonList;

从表面上看,上述代码非常完美,但是深入一点,我们会发现一个缺点:删除列表中的某个指针时,该指针是一个空指针,而删除一个空指针与删除一个TButton型的指针是不同的,因为删除一个空指针不能自动执行一个对象的析构函数,也就不能执行析构函数中的内存释放与重新分配操作,从而会造成内存空洞。

为了能正确删除TList对象中的指针,必须将它们的类型进行转换,这样编译器才能正确调用类的析构函数。因为VCL中的所有析构函数都是虚函数,我们可以将列表中的所有转换为一个公共的基类,例如:

TList *ControlList = new TList;   

ControlList->Add(new TButton(Handle));

    ControlList->Add(new TEdit(Handle));

ControlList->Add(new TComboBox(Handle));   

int nCount = ControlList->Count;

    for (int j=0; j<nCount; j++)

        delete reinterpret_cast<TWinControl *>(ControlList->Items[j]);

delete ControlList;

TList对象中的指针对象都是从TWinControl继承下来的,则上述代码工作正确,若某指针对象是从TDataSet继承下来的,则上述代码工作又有问题。

二、改进方法

如果TList知道它所处理的对象,那么它的许多缺点就自动消除。基于此,在TList的基础上我们引进了一个新类TTypedList,它是从TList继承下来的一个模板类,它在TList方法的基础上提供了强制类型检查,同时也提供了自动删除列表中的指针的一个方法。代码如下:

//--------------------------------------------------------------

#ifndef TTYPEDLIST_H   

#define TTYPEDLIST_H

#include <classes.hpp>

template <class T>   

class TTypedList : public TList   

{   

private:

        bool  bAutoDelete;   

protected:       

T* __fastcall Get(int Index)

{           

return (T*) TList::Get(Index);       

 }

void __fastcall Put(int Index, T* Item)       

{

TList::Put(Index,Item);       

 }    

public:

__fastcall TTypedList(bool bFreeObjects = false)         

:TList(),

bAutoDelete(bFreeObjects)       

{       

}

int __fastcall Add(T* Item)       

{           

    return TList::Add(Item);

}       

void __fastcall Delete(int Index)       

{

        if(bAutoDelete)               

            delete Get(Index);

        TList::Delete(Index);       

}       

void __fastcall Clear(void)

{           

    if(bAutoDelete)           

    {

            for (int j=0; j<Count; j++)                    

              delete Items[j];

        }

        TList::Clear();       

    }

T* __fastcall First(void)       

{           

    return (T*)TList::First();

}       

int __fastcall IndexOf(T* Item)       

{

        return TList::IndexOf(Item);        

    }

void __fastcall Insert(int Index, T* Item)       

{

        TList::Insert(Index,Item);       

}       

T* __fastcall Last(void)

{           

    return (T*) TList::Last();       

}

int __fastcall Remove(T* Item)       

{

        int nIndex = TList::Remove(Item);

        if(bAutoDelete && (nIndex != -1))               

            delete Item;

        return nIndex;       

    }

__property T* Items[int Index] = {read=Get, write=Put};   

};   

#endif

 

    最后根据改进的TTypedList类举个例了:

  在C++ Builder4中建一个新的应用程序,主要代码如下:

#include <vcl.h>

#pragma hdrstop

 

#include "Unit1.h"

#include "typedlist.h"

 

//---------------------------------------------------------------------

#pragma package(smart_init)

#pragma resource "*.dfm"

TForm1 *Form1;

//---------------------------------------------------------------------__fastcall TForm1::TForm1(TComponent* Owner)

        : TForm(Owner)

{

}

//---------------------------------------------------------------------

 

void __fastcall TForm1::CreateButtons()

{

// Create a list of buttons.

TTypedList <TButton> *ButtonList = new TTypedList <TButton>(false);

ButtonList->Add(new TButton(this));   

ButtonList->Add(new TButton(this));

    ButtonList->Add(new TButton(this));

for (int j=0; j<ButtonList->Count; j++)   

{

        ButtonList->Items[j]->Caption = "Button" + IntToStr(j);

        ButtonList->Items[j]->Left    = 250;

        ButtonList->Items[j]->Top     = 50 + j*25;

        ButtonList->Items[j]->Parent  = this;   

}   

delete ButtonList;

  }

//-------------------------------------------------------------------------

void __fastcall TForm1::FormShow(TObject *Sender)

{

CreateButtons();

}

//-------------------------------------------------------------------------以上代码在C++ Builder5+Pwin2000 Professional环境下中通过。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
参考链接:https://msdn.microsoft.com/en-us/library/windows/hardware/ff558903%28v=vs.85%29.aspx Parameters tlist Without additional parameters, TList displays all running processes, their process identifiers (PIDs), and the title of the window in which they are running, if any. /p ProcessName Displays the process identifier (PID) of the specified process. ProcessName is the name of the process (with or without file name extension), not a pattern. If the value of ProcessName does not match any running process, TList displays -1. If it matches more than one process name, TList displays only the PID of the first matching process. PID Displays detailed information about the process specified by the PID. For information about the display, see the "Remarks" section below. To find a process ID, type tlist without additional parameter. Pattern Displays detailed information about all processes whose names or window titles match the specified pattern. Pattern can be a complete name or a regular expression. /t Displays a task tree in which each process appears as a child of the process that created it. /c Displays the command line that started each process. /e Displays the session identifier for each process. /k Displays the COM components active in each process. /m Module Lists tasks in which the specified DLL or executable module is loaded. Module can be a complete module name or a module name pattern. /s Displays the services that are active in each process. /v Displays details of running processes including the process ID, session ID, window title, command line, and the services running in the process. 。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值