标准模版容器类vector提供了统一的操作接口,但也有不方便的地方,主要是不便直接操纵其内存指针。
下面是我自定义的模版容器类XList<T>,已使用过多年,经过了比较充分的检验。
模版容器的一个关键操作就是当容器需要增加内存的时候(参考ReallocMem成员函数),如何拷贝对象,
有下面三种操作模式:
A.可以对整个序列使用memcpy, memset, 这样对简单并且比较一般的对象效率高;
B.要对每个对象使用operator=;
C.使用对象的成员函数TransTo(数据转移,相当于右值引用),这样对复杂的对象高效安全;
这三种模式对应下面的三个类。
还有一点值得说明的是,XList 提供了缓存机制(参考其数据成员pBufMem)。
//为方便使用该模板类, 其主要成员为public, 慎用该类!
template <typename X>
class XList //使用 memcpy, memset, 也使用了 operator=
{
public:
int xmem;
int xnum;
X* pxs;
protected:
X* pBufMem; //内存缓冲区(频繁使用时减少内存分配次数), 由使用者提供,不要释放!
public:
XList(int xm=0):xmem(0),xnum(0),pxs(0),pBufMem(0){
if(xm>0) EnsureMem(xm);
};
~XList(){
FreeMem();
};
XList(const XList& r){
InitFrom(r);
};
void operator=(const XList& r){
if(pxs){
if(pxs!=pBufMem) delete[] pxs;
pxs=0;
}
InitFrom(r);
};
bool IsTmpObj() const{//是否为临时对象,释放临时对象的内存是危险的!
return (xnum>0 && xmem==0);
};
void TransFrom(XList& from){
ASSERT(this!=&from);
FreeMem();
memcpy(this, &from, sizeof(XList<X>));
memset(&from, 0, sizeof(XList<X>));
};
void TransTo(XList& to){
ASSERT(this!=&to);
to.FreeMem();
memcpy(&to, this, sizeof(XList<X>));
memset(this, 0, sizeof(XList<X>));
};
//初始化内存缓冲区
void InitMemBuf(X* pBuf, int m){
ASSERT(pxs==0 && m>0);
pBufMem= pBuf;
pxs= pBuf;
xmem= m;
xnum= 0;
};
void FreeMem(){
if(xmem && pxs){
if(pxs!=pBufMem) delete[] pxs;
pxs=0;
}
xmem= 0;
};
void Clear(){
FreeMem();
xnum=0;
};
//EnsureMem: 保证拥有指定数量的内存, 使用 ReallocMem !
bool EnsureMem(int mem){
if(mem>xmem){
return ReallocMem(mem, true);
}
return true;
};
protected:
//virtual? ReallocMem: 使用 memcpy, memset !
bool ReallocMem(int mem, bool freeMem){
ASSERT(!IsTmpObj()); //临时对象不允许写操作!
if(mem<4)//自动执行内存增长
mem= AddMemAuto();
X *pNew= new X[mem];
// TRACE("XList::ReallocMem pNew = 0x%08x\n",pNew);
if(pNew==0){
TRACE("XList::ReallocMem() failed!\n");
return false;
}
if(pxs){
if(xnum>0)
memcpy(pNew, pxs, sizeof(X)*xnum);
if(freeMem && xmem){
memset(pxs, 0, sizeof(X)*xnum);
if(pxs!=pBufMem) delete[] pxs;
}
}
pxs= pNew;
xmem= mem;
return true;
};
public:
void Init0(){
xmem= 0;
xnum= 0;
pxs= 0;
};
bool IsNull() const{
return (pxs==0 || xnum==0);
};
bool IsValid() const{
return (pxs && xnum>0);
};
int Add(const X& x){//quick add(拷贝对象)不检查内存
ASSERT(xnum<xmem);
pxs[xnum++]= x;
return 1;
};
int AddEx(X& x){//quick add(转移对象)不检查内存
ASSERT(xnum<xmem);
memcpy(pxs+xnum, &x, sizeof(X));
memset(&x, 0, sizeof(X));
++xnum;
return 1;
};
int AddOne(const X& x){ //拷贝对象:使用 operator=
if(xnum==xmem){
X* pold= pxs; //考虑 AddOne(pxs[0])!
if(!ReallocMem(0, false))
return 0;
pxs[xnum]= x;
if(pold){
memset(pold, 0, sizeof(X)*xnum);
if(pold!=pBufMem) delete[] pold;
}
++xnum;
}
else
pxs[xnum++]= x;
return 1;
};
int AddOneEx(X& x){//转移对象:使用 memcpy, memset
if(xnum==xmem){
X* pold= pxs; //考虑 AddOne(pxs[0])!
if(!ReallocMem(0, false))
return 0;
memcpy(pxs+xnum, &x, sizeof(X));
if(pold){
memset(pold, 0, sizeof(X)*xnum);
if(pold!=pBufMem) delete[] pold;
}
}
else
memcpy(pxs+xnum, &x, sizeof(X));
memset(&x, 0, sizeof(X));
++xnum;
return 1;
};
//检查是否已经有相同的元素
int AddOneNoEqual(const X& x){
for(int k=0; k<xnum; k++){
if(pxs[k]==x)
return 0;
}
AddOne(x);
return 1;
};
void operator+= (const XList<X>& lst){
if(lst.IsValid()){
ASSERT(lst.pxs!=pxs);
EnsureMem(xnum+lst.xnum);
memcpy(pxs+xnum, lst.pxs, sizeof(X)*lst.xnum);
xnum+= lst.xnum;
}
};
//注意: 两种形式的operator[]
//为方便使用而提供的, 建议直接使用指针pxs!
X& operator []( int k ){//用法: XList[k]= x;
ASSERT(pxs);
return pxs[k];
};
const X& operator []( int k ) const{//用法: x= XList[k];
ASSERT(pxs);
return pxs[k];
};
const X& Last() const{
ASSERT(pxs);
return pxs[xnum-1];
};
void Revert(){
const int H= (xnum>>1);
int k,n= xnum-1;
X t;
for(k=0; k<H; k++){
t= pxs[k];
pxs[k]= pxs[n];
pxs[n--]= t;
}
};
protected:
//自动内存增长策略
int AddMemAuto() const{
int add;
if(xmem<64)//倍增
add= max(4, xmem);
else//半增
add= (xmem>>1);
return (xmem+add);
};
void InitFrom(const XList& r){
xmem= r.xmem;
xnum= r.xnum;
if(xmem>0){
pxs= new X[xmem];
// TRACE("pxs = 0x%08x\n",pxs);
}
else
pxs= 0;
if(xnum>0){
// memcpy(pxs, r.pxs, sizeof(X)*xnum);
for(int k=0; k<xnum; ++k)
pxs[k]= r.pxs[k];
}
};
};
//XListEx: use TransTo in ReallocMem!
template <typename X>
class XListEx: public XList<X>
{
public:
XListEx(int xm=0):XList<X>(xm){};
~XListEx(){};
XListEx(const XListEx& r){
InitFrom(r);
};
void operator=(const XListEx& r){
if(pxs){
if(pxs!=pBufMem) delete[] pxs;
pxs=0;
}
InitFrom(r);
};
protected:
//virtual? ReallocMem: 不使用 memcpy, memset,而是使用 TransTo !
bool ReallocMem(int mem, bool freeMem){
ASSERT(!IsTmpObj()); //临时对象不允许写操作!
if(mem<4)
mem= AddMemAuto();
X *pNew= new X[mem];
// TRACE("XListEx::ReallocMem: pNew = 0x%08x\n",pNew);
if(pNew==0){
TRACE("XListEx::ReallocMem() failed!\n");
return false;
}
if(pxs){
if(xnum>0){
for(int k=0; k<xnum; k++)
pxs[k].TransTo(pNew[k]);
}
if(freeMem && xmem){
if(pxs!=pBufMem) delete[] pxs;
}
}
pxs= pNew;
xmem= mem;
return true;
};
public:
//不提供实现,屏蔽掉这两个基类成员函数!
int Add(const X& x);
int AddOne(const X& x);
void operator+= (const XListEx<X>& lst);
int AddEx(X& x){//quick add, 不检查内存
ASSERT(xnum<xmem);
x.TransTo(pxs[xnum]);
++xnum;
return 1;
};
int AddOneEx(X& x){
if(xnum==xmem){
X* pold= pxs;
if(!ReallocMem(0, false))
return 0;
x.TransTo(pxs[xnum]);
if(pold){
if(pold!=pBufMem) delete[] pold;
}
}
else
x.TransTo(pxs[xnum]);
++xnum;
return 1;
};
void Revert(){
const int H= (xnum>>1);
int k,n= xnum-1;
X t;
for(k=0; k<H; k++){
pxs[k].TransTo(t);
pxs[n].TransTo(pxs[k]);
t.TransTo(pxs[n]);
--n;
}
}
};
//XList11: using operator=, 一个一个的copy in ReallocMem!
template <typename X>
class XList11: public XList<X>
{
public:
XList11(int xm=0):XList<X>(xm){};
~XList11(){};
XList11(const XList11& r){
InitFrom(r);
};
void operator=(const XList11& r){
if(pxs){
if(pxs!=pBufMem) delete[] pxs;
pxs=0;
}
InitFrom(r);
};
protected:
//virtual? ReallocMem: 使用 operator= !
bool ReallocMem(int mem, bool freeMem){
ASSERT(!IsTmpObj()); //临时对象不允许写操作!
if(mem<4)
mem= AddMemAuto();
X *pNew=new X[mem];
// TRACE("XList11::ReallocMem pNew = 0x%08x\n",pNew);
if(pNew==0){
TRACE("XList11::ReallocMem() failed!\n");
return false;
}
if(pxs){
for(int k=0; k<xnum; ++k)
pNew[k]= pxs[k];
if(freeMem && xmem){
if(pxs!=pBufMem) delete[] pxs;
}
}
pxs= pNew;
xmem= mem;
return true;
};
public:
int AddEx(X& x){//quick add, 不检查内存
Add(x);
return 1;
};
int AddOneEx(X& x){
AddOne(x);
return 1;
};
void operator+= (const XList11<X>& lst){
if(lst.IsValid()){
EnsureMem(xnum+lst.xnum);
for(int k=0; k<lst.xnum; ++k)
pxs[xnum++]= lst.pxs[k];
}
};
};