C++多么多么强大,对内存的控制细致入微,但优点同时即是缺点,你必须清楚的记得你new出来的每一块内存是怎么释放的。所以C++/CLI才把拖管方式引进来,弥补这个问题。我现在不是要讨论C++/CLI,而是传统C++。
以前在写课程设计FileSolvent时就做过这种尝试,让类自己管理内存,简单的说,对象在觉得自己该释放的时候就释放,到最后都没释放的就统一释放。但这样必须要做到的就是有一个列表保存了这个类每一个实例的指针。这并不难,只有给这个类添加一个静态列表成员,然后在构造函数里把自己加进去,在析构函数里再把自己拿出来就行了:
class
SomeClass
... {
static vector<SomeClass*> list;
public:
SomeClass() ...{ list.push_back(this); }
~SomeClass() ...{ list.remove(this); }
} ;
vector < SomeClass *> SomeClass::list; // VC中静态成员变量需要这样初始化一下
... {
static vector<SomeClass*> list;
public:
SomeClass() ...{ list.push_back(this); }
~SomeClass() ...{ list.remove(this); }
} ;
vector < SomeClass *> SomeClass::list; // VC中静态成员变量需要这样初始化一下
只要再给这个list写一个getter,就可以从外面访问这个类型现存的所有实例了。
但如果要让多个类带有这种功能,难道给每个类都添加这段代码吗?这显然不是个好想法。一种思路是使用继承,在基类中写好这些逻辑,子类是你想要的类,但很不幸的,所有子类会共享基类的静态成员,也就是只会有一个list,所有的实例指针都会放进去,那时RTTI会烦死人的。
难道就没有更好的办法了吗?当然会有,我从ATL中受到启发,只要把基类做成模板类,以子类名作为模板参数,只要是不同的子类,就会自己编译出不同的基类,也就会有不同的静态成员,哈,这正是我想要的。
下面的代码写出来和ATL感觉好像啊:
template
<
class
T
>
//
以子类为模板参数
class ISelfMemMgr
... {
private:
static std::vector<T*> instanceList; //这就是容纳所有实例指针的静态列表
protected:
ISelfMemMgr(void)
...{
T* pThis = static_cast<T*>(this); //必须转换为子类指针,要不然是加不进去的
instanceList.push_back(pThis);
}
virtual ~ISelfMemMgr(void)
...{
T* pThis = static_cast<T*>(this);
instanceList.remove(pThis);
}
} ;
class ISelfMemMgr
... {
private:
static std::vector<T*> instanceList; //这就是容纳所有实例指针的静态列表
protected:
ISelfMemMgr(void)
...{
T* pThis = static_cast<T*>(this); //必须转换为子类指针,要不然是加不进去的
instanceList.push_back(pThis);
}
virtual ~ISelfMemMgr(void)
...{
T* pThis = static_cast<T*>(this);
instanceList.remove(pThis);
}
} ;
这样一来,子类真的只要继承这个基类就够了。但问题还没完,前面所说的目标是要释放的时候尽管释放,没释放的到最后一起释放,怎么实现这个最后一起释放呢?在OnDestroy()里释放吗?当然不好,一方面需要多写代码,忘写了就完了;另一方面这样只对MFC程序有效,我希望这个程序的可复用性更强。其实,不就是想要在程序即将结束时知道一下吗,这种情况C++早就为我们提供了最佳的处理方式:对于全局变量和类静态成员,都会在程序即将结束时被自动析构的,只要在这个析构函数里写点什么就达到目的了。
为此,再添加一个Helper类,目的就是程序结果时释放内存。而且,为了和前述类能够配套使用,这里也使用模板类的形式:
template < class T >
class SelfMemMgrHelper
... {
public:
~SelfMemMgrHelper()
...{
ISelfMemMgr<T>::FinalDelete(); //就是这里要释放全部变量,它会被自动调用
}
private:
SelfMemMgrHelper() //构造函数声明为私有,防止从外面生成实例
...{}
} ;
然后,再把这两个类互设友元,并且在前面类里面再加一个Helper类的静态成员。并且,为了防止使用时过于麻烦,免去使用者手写静态成员初使化的过程,可以把它封装成一个宏(越来越像ATL):
#define
DECLARE_SELFMEMMGR_HEAD(type) std::vector< type* > ISelfMemMgr< type >::instanceList;
SelfMemMgrHelper < type > ISelfMemMgr < type > ::helper;
SelfMemMgrHelper < type > ISelfMemMgr < type > ::helper;
现在使用时只需要这样:
class
SomeClass:
public
ISelfMemMgr
<
SomeClass
>
... {
...
} ;
DECLARE_SELFMEMMGR_HEAD(SomeClass)
... {
...
} ;
DECLARE_SELFMEMMGR_HEAD(SomeClass)
就这么简单,不再需要其他的辅助内容了。
当然,现在算不上完美,例如还没有考虑上并发控制问题,这就是以后的事了。
附完整的代码如下:
#pragma once
#include < vector >
template < class T >
class SelfMemMgrHelper;
template < class T >
class ISelfMemMgr
... {
friend class SelfMemMgrHelper<T>;
public:
static std::vector<T*>& GetInstances() ...{ return instanceList; }
private:
static std::vector<T*> instanceList;
static SelfMemMgrHelper<T> helper;
protected:
ISelfMemMgr(void)
...{
T* pThis = static_cast<T*>(this);
instanceList.push_back(pThis);
}
virtual ~ISelfMemMgr(void)
...{
T* pThis = static_cast<T*>(this);
for(std::vector<T*>::iterator it = instanceList.begin(); it != instanceList.end(); it++)
...{
if(*it == pThis)
...{
instanceList.erase(it);
break;
}
}
}
private:
static void FinalDelete()
...{
while(!instanceList.empty())
...{
delete *instanceList.begin();
}
}
} ;
template < class T >
class SelfMemMgrHelper
... {
friend class ISelfMemMgr<T>;
public:
~SelfMemMgrHelper()
...{
ISelfMemMgr<T>::FinalDelete();
}
private:
SelfMemMgrHelper()
...{}
} ;
#define DECLARE_SELFMEMMGR_HEAD(type) std::vector< type* > ISelfMemMgr< type >::instanceList;
SelfMemMgrHelper < type > ISelfMemMgr < type > ::helper;