很久没有用心的读过一本书了,今天静下心来,认真的看了过去一直在看的云风的书(游戏之旅-我的编程感悟)。这本书从两个月前都开始看,吊吊当当的持续到现在,很多章节浅尝辄止。说实话,有些章节是真心看不懂。看看大牛们的书,自己真是羞愧难当。没办法,既然难以望其项背,自己唯而加快奔跑。今天仔细阅读了C++的一章,受益不少,谨以此记录以备忘。
1. template的使用技巧
1.1. 封装c++的成员函数调用
这个类需要在调用成员函数的之前和之后自动调用call和return函数。例如欲记录函数的调用历史,作一些前期分配和后期清理的工作。
class monitor
{
void call() {}
void return() {}
}
如何实现这种技巧? 仔细思考应该是借用临时对象的特性,在临时对象的构造函数中调用call,在析构函数调用return,但是要注意的是必须能够在调用成员函数的时候,创建一个临时对象。
template <typename T>
class WrapFunction
{
private:
WrapFunction();
WrapFunction(const WrapFunction&);
WrapFunction& operator=(const WrapFunction&);
T* m_pT;
private:
class CallHelper
{
private:
T* m_pT;
CallHelper(T* p): m_pT(p){}
public:
~CallHelper(){
m_pT->after();
}
T* operator->()const
{
return m_pT;
}
friend class WrapFunction<T>;
};
public:
WrapFunction(T& obj): m_pT(&obj){}
CallHelper operator->() const
{
m_pT->before();
return CallHelper(m_pT);
}
};
如何使用:
Test obj;
WrapFunction<Test> t(obj);
t->print();
主要有几个技术点:
- 如何调用before函数?可以通过WrapFunction重载->运算符
- 为什么要使用CallHelper这个类呢? 由于需要在调用print结束之后调用after。
- 使用了局部对象析构的策略,在析构中调用after。
- 使用了友元类的方案来使得CallHelper的构造函数私有化,以避免外部可能使用此CallHelper类。
- CallHelper类中也使用了m_pT指针,以使得外面的m_pT可以定义为私有,避免外部使用。
- 有几个技术都是为了使外部类WrapFunction的方法尽量私有化,仅仅公开两个方法。一个构造函数,一个重载。
- 禁止默认构造,copy,赋值
1.2. 对象计数
项目中出现内存不断扩张,重载operator new也没有发现未释放的对象。只好通过给项目中的每一个类增加一个对象计数器来跟踪对象的创建情况。仔细思考,假定要跟踪类A的对象创建个数,外面有一个全局计数器CA,那么需要在类A中增加一个非静态的成员变量,这个成员变量能够保证在构造的时候(创建A的对象)增加全局计数器,即CA++,在析构的时候减少全局计数器,即CA--。通过这种方式,可以用全局计数器记录了A对象的创建。同理,跟踪B类的对象个数,需要全局计数器CB。这也就是说,我们需要使用类的模板,并且这个类的模板的有一个静态数据成员,充当全局计数器的作用。使用哪个类进行模板实例化,就创建哪个类的全局计数器。代码如下所示:
class counter_data
{
public:
counter_data(const char* name) :_name(name){
printf("name:%s this:%p\n", name, this);
}
~counter_data(){
printf("name:%s this:%p count:%d\n", _name, this, current_count());
}
void inc()
{
if(++_counter > _max){
_max = _counter;
}
}
void dec()
{
--_counter;
assert(_counter >= 0);
}
int current_count() const{
return _counter;
}
int max_count() const{
return _max;
}
private:
int _max;
int _counter;
const char* _name;
};
template <typename T>
class counter
{
public:
counter() {_data.inc();}
counter(const counter& rhs){
_data.inc();
}
~counter(){
_data.dec();
}
public:
int current_count()const {
return _data.current_count();
}
int max_count() const{
return _data.max_count();
}
private:
static counter_data _data;
};
template<typename T>
counter_data counter<T>::_data(typeid(T).name());
如何使用它?只需要添加一个私有实例变量即可。
class Object
{
public:
~Object(){
printf("Object count:%d\n", _couter.current_count());
}
private:
counter<Object> _couter;
};
解释:
counter是一个模板类,它持有一个静态数据成员_data。由于此模板类的模板参数类型是T, 也就是各种要被计数的对象类型,那也就是说会有多个counter类的实现,也就是会有多个_data对象。counter_data在创建的时候会注册name和自身指针,可以通过在counter_data类中添加更详细的log来详细跟踪Object对象的创建过程。