前面簡單介紹了Aspect C++,相信沒人看出它有什么特別強大的地方。
這次特別挑了一個合適的例子,檢查內(nèi)存泄漏。
首先看一個普通的程序:
1、test.h
#ifndef __TEST_H__
#define __TEST_H__
class Test1
{
};
class Test2
{
};
class Test3
{
};
#endif // __TEST_H__
2、main.cc
#include "test.h"
int main ()
{
Test1 test1;
Test2 test2;
Test3 test3;
new Test1();
new Test2();
new Test2();
new Test1();
new Test1(test1);
new Test3(test3);
return 0;
}
這個程序會有6個對象泄漏。如果是在很隱蔽的地方分配對象,如何能夠快速查找出來呢?
采用Aspect C++,我們可以在構(gòu)造函數(shù)和析構(gòu)函數(shù)中插入代碼,幫助檢查內(nèi)存泄漏。
首先實現(xiàn)一個內(nèi)存分配記錄管理器:
1、memory_recorder.h
#ifndef __MEMORY_RECORDER_H__
#define __MEMORY_RECORDER_H__
#include <map>
#include <typeinfo>
using namespace std;
class MemoryRecorder
{
map<void*, const type_info*> objects;
public:
~MemoryRecorder ();
void addObject(void* obj, const type_info& ti);
void removeObject(void* obj, const type_info& ti);
};
extern MemoryRecorder g_memoryRecorder;
#endif // __MEMORY_RECORDER_H__
2、memory_recorder.cc
#include "memory_recorder.h"
#include <iostream>
using namespace std;
MemoryRecorder g_memoryRecorder;
MemoryRecorder::~MemoryRecorder ()
{
if (objects.size() > 0)
{
cout << objects.size() << " objects not released:" << endl;
for (map<void*, const type_info*>::const_iterator iter = objects.begin();
iter != objects.end();
iter ++)
{
cout << "\t" << iter->second->name() << ": " << (iter->first) << endl;
delete (iter->first);
}
}
}
void MemoryRecorder::addObject(void* obj, const type_info& ti)
{
objects.insert(make_pair(obj, &ti));
}
void MemoryRecorder::removeObject(void* obj, const type_info& ti)
{
objects.erase(obj);
}
3、實現(xiàn)方面,test.ah
#ifndef __TEST_AH__
#define __TEST_AH__
#include "memory_recorder.h"
#include <iostream>
using namespace std;
aspect MemberRecorder
{
pointcut all_class() = classes("Test%");
advice construction (all_class()) : after ()
{
g_memoryRecorder.addObject (tjp->target(), typeid(*tjp->target()));
}
advice destruction (all_class()) : after ()
{
g_memoryRecorder.removeObject (tjp->target(), typeid(*tjp->target()));
}
};
#endif // __TEST_AH__
這個方面實現(xiàn)的功能很簡單,首先定義了一個pointcut(切面),它匹配所有以“Test”開頭的類。
接下來定義了2個處理方法,分別在這些類的構(gòu)造函數(shù)和析構(gòu)函數(shù)調(diào)用之后執(zhí)行。
tjp->target()指向Test*對象實例,其它的不詳細說明了,應該都比較容易懂。
順便說一下,前一篇里說源文件可以保存為.cpp文件,實際上是錯誤的,它只處理.h和.cc文件。
運行ac++產(chǎn)生代碼,編譯運行后效果如下:
F:\projects\aspectc-out>main
6 objects not released:
class Test1: 00372B40
class Test1: 00372B70
class Test3: 00372BA0
class Test1: 00374F90
class Test2: 00374FC0
class Test2: 00374FF0
另外,產(chǎn)生代碼時最好是使用mingw,配置方便一些,不影響產(chǎn)生后的代碼,產(chǎn)生后的代碼可以使用VC編譯。