前面简单介绍了Aspect C++,相信没人看出它有什么特别强大的地方。
这次特别挑了一个合适的例子,检查内存泄漏。
首先看一个普通的程序:
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++,我们可以在构造函数和析构函数中插入代码,帮助检查内存泄漏。
首先实现一个内存分配记录管理器:
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、实现方面,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__
这个方面实现的功能很简单,首先定义了一个pointcut(切面),它匹配所有以“Test”开头的类。
接下来定义了2个处理方法,分别在这些类的构造函数和析构函数调用之后执行。
tjp->target()指向Test*对象实例,其它的不详细说明了,应该都比较容易懂。
顺便说一下,前一篇里说源文件可以保存为.cpp文件,实际上是错误的,它只处理.h和.cc文件。
运行ac++产生代码,编译运行后效果如下:
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
另外,产生代码时最好是使用mingw,配置方便一些,不影响产生后的代码,产生后的代码可以使用VC编译。