在前文《C++的模板(八):子系統》class DMM,給出了一個自動動態內存管理的例子。https://blog.csdn.net/aaasssdddd96/article/details/139921880
它使用了一個list容器,把兩個類型兼容的指針存放在一起。在new的時候,隨即就把得到的指針放進了list容器里。在管理器析構的時候,自動釋放容器中的指針。這樣避免了手動釋放內存的問題。指針new出來就可以用了,不用自己釋放,也不用擔心內存泄漏。
現在做一點改造。采用更多的list容器來管理不同的new類型。讓幾乎每一種類型可以同樣自動管理。根據前文的例子,問題的后一半已經有了答案,現在只要把list容器組裝起來。
考慮到每個list容器,如list<int>,list<double>,原則上雖然都是list,具體到語法上卻都是不同的類型。要把它們調整到一致。前文《C++的繼承(十二):抽象類》給出了一種方法。https://blog.csdn.net/aaasssdddd96/article/details/146153593
如果還記得“吃餃子要沾點醋”這句話,現在就來用一下。就是讓它們都繼承一個空的抽象類。一個空的抽象類好比是“要沾的醋”。
class E{
public:
virtual ~E() {printf("~E\n");}
};
template <class C>
class M: public E
{
public:list<C*> l;C *newobj(C x) {C *p = new C(x);l.push_back(p);}~M() {printf("type: M<%s>:\n", typeid(C).name());typename list<C*>::iterator it;for(it=l.begin(); it!=l.end(); ++it) {if(typeid(C)==typeid(int)) {printf("%d ", *(int*)*it);}else if(typeid(C)==typeid(double)) {printf("%lf ", *(double*)*it);} else printf(". ");delete *it;}printf("/.\n");}
};
各種list容器已經包裝到了class M中,并且繼承了共同的空類E。
現在把這些包裝過的list容器組裝進map模板。用內存分配的目標類型的typeid來進行索引。注意雖然是用typeid來進行索引這個概念。在具體實現上,由于編譯器typeid返回的type_info類型做成了固定的const 類型,并且屏蔽了構造函數,復制,賦值這些操作,不能直接用它來構造map容器。需要用個代理來做這些事情。
class typeinfop {const type_info *tp;
public:typeinfop(const type_info *p){tp=p;}bool less(const type_info *t)const {return tp->before( *t);}bool operator<(const typeinfop p) const {return less(p.tp);}
};
這個typeinfop將作為map模板的key來使用。注意作為map模板的key必須定義operator<()比較運算。
接下來就定義一個封裝了map模板的簡單類class SE。因為各種list容器已經統一繼承了空類E。map模板的類型就是 map<typeinfop, E*>。類中含有一個newobj()模板成員函數和一個析構函數。析構函數會自動刪除用E類包裝的list容器。而這些list容器在析構時,又會自動刪除內存分配new出去的對象指針。
class SE {map<typeinfop, E*> m;
public:template<class C>C *newobj(C x) {E* p;M<C> *mp;p = m[typeinfop(&typeid(C))];if(!p) {p = new M<C>;m[typeinfop(&typeid(C))]=p;}mp = static_cast<M<C>*> (p);return mp->newobj(x);}~SE() {map<typeinfop, E*>::iterator it;for(it=m.begin(); it!=m.end(); ++it) {delete it->second;}}
}sm;
這就大功告成了。現在寫個main()函數測試下看效果,new出來就不用管了:
#include <stdio.h>
#include <stdlib.h>
#include <list>
#include <map>
#include <typeinfo>
using namespace std;
int main()
{int *p;double *dp;dp= sm.newobj(3.1);p= sm.newobj(3);dp= sm.newobj(3.14);p= sm.newobj(4);dp= sm.newobj(3.141);p= sm.newobj(5);dp= sm.newobj(3.1415);int **pp = sm.newobj(p);double **dpp = sm.newobj(dp);return 0;
}
運行結果:
type: M<Pd>:
. /.
~E
type: M<Pi>:
. /.
~E
type: M<d>:
3.100000 3.140000 3.141000 3.141500 /.
~E
type: M<i>:
3 4 5 /.
~E
sm內存管理器自動生成了4個list容器。分別是list<double*>,list<int*>,list<double>和list<int>。打印的信息是析構函數里輸出的,分配的每一個數據都得到了刪除處理。