由于benchmark的抽象逻辑很简单,但复杂而且易变的部分在其底层的I/O解析部分。所以设计起来有点尴尬:太抽象,本身逻辑很清晰,但会加重下层逻辑的负担,换一个协议时,下层逻辑需要动的部分太多;减少抽象,逻辑上就比较模糊,比如抽象在I/O解析部分,则对于每一个协议都可以很快的实现,但是造成benchmark可能需要不停的适应新协议的变化,不够通用。以下时碰到的几个问题:
1)静态成员变量。
static修饰的成员变量,即静态成员。一般用来解决所有实例共享数据的问题,或者说所有类共有的属性、特征。但是有个很矛盾的事实是,他使用起来很丑陋。如果共享的是一个常量,那还可以,如果是一个对象或者对象引用,就麻烦了,你得在一个合适的(共享对象创建后)地方给静态变量赋值,并且赋值语句可能在整个代码流程中显的比较丑陋,怪异,比如:在一个函数中突然来一个:
void foo() {
ClassA *a = new ClassA;
a.Init();
..............
ClassB::ptr_A = a;
..........
}
我是觉得很丑陋。有一个解决方法,但只适用于在全局范围内,共享的实例只有一个。在ClassA的构造中添加: ClassB::ptr_A = this; 其实逻辑上也不好,ClassB关A什么事情呢?为什么A要在自己的构造中给B好处呢?
我觉得静态成员变量要慎用。
2)自我管理类
如果我们不想引入一个类来专门管理一些数量在变化中,并且管理比较分散类实例时。可以构建该类自己的管理机制,我称之为垃圾回收、再利用机制。这种类型的类有个比较奇怪的特性:动态分配实例可能再类外部,或者类内部。而释放实例的动作由实例内部触发。一般释放时我们不会去使用delete this这样古怪的语言。那么既然实例自己不能使用delete,就把自己放入一个静态的类中的垃圾回收器。最后由类外部的程序来释放垃圾。当然这样的好处还有分配实例时,可以直接从垃圾堆里取一个出来,避免了动态的开销。这样的类声明的例子:
class CManageMyself
{
public:
.....................
public:
void DestroyAll(); // call by outer code
private:
void GarbageCollect(CManageMyself *mm); // push mm to garbage collector
CManageMyself *GetInstance() {
CManageMyself *mm;
if ( there's no garbages ) {
mm = new CManageMyself;
return mm;
}
// get a garbage from collector
return garbages.pop();
}
}
3)低耦合
当然这个是面向对象设计的原则。尽量保持类于类之间低耦合性
4)多个类声明中互相声明对方类指针
这个情况的出现,已经一定程度上违背3条。不过没办法。必须注意的是,在互相引用声明中,最好只在一个类声明文件中包含另一个类的头文件,而后者的头文件里,不要包含前者的头文件,只要简单的在类声明前声明一下另一个类的类型。如:
// classA.h
#include "classB.h"
class classA {
classB *pb;
}
// classB.h
class classA;
class classB {
classA *pa;
}
否则编译会通不过,道理很简单。千万别帮这个方法用在声明对方类上面来,只能是指针。否则编译器不能得知类实例的大小,编译无法通过。
5)限定模板参数类型
有时候我们需要限定一下模板参数的类型。当然最好是让编译器来检查。最easy的方法是,在模板类中调用改限定类型的某些特定方法,或者变量。实在不行就利用boost吧:
// declarative way, overloadable!
template
void foo(T t, typename boost::enable_if< boost::is_base_of,int >::type = 0)
{
// do your business here!
}
// imperative way, can't be used in overload resolution!
template
void foo1(T t)
{
BOOST_STATIC_ASSERT( (boost::is_base_of::value) );
// do your business here!
}
参考:
阅读(2098) | 评论(0) | 转发(0) |