??xml version="1.0" encoding="utf-8" standalone="yes"?>
通过try catch来捕捉异?br />try
{
pMemory = new char[MAX_BUF_SIZE];
}
catch(std::bad_alloc& e)
{
//error handling,er:do something resource free
}
但在E序代码D中出现大量的try catch,不仅从美观,效率和程序输写上都是不怎么好?br />而另外一U对于异常的处理Ҏ是依赖于c++的ctor/dctor的匹配来做的Q就是所谓的
RAII,q个很容易让惛_std::auto_ptr
std::auto_ptr<int> tmp(new int);
通过new分配的对象会在tmp生命l束后,释放相关的资源,通过q种方式Q就能保证在E序异常Q或退出时Q已分配的对象能正确自动的释放拥有的资源Q而在对象声明周期内,可以保证资源的有效性?br />q种方式是今天blog要写的主要内容,我们可以看到std::auto_ptr作用范围很小Q只能对从堆上分配的对象q行理Q假如对文g打开句柄实行RAII,你也怼认ؓ再写个不是了,但这样只会造成源代码里充满了这些资源管理的c,q导致了一个严重的问题Q好的结构在J琐的流畅前面变的难堪?br />那怎么样对q个q行泛化Q从而能Ҏ如从单的指针释放Q文件句柄维护,甚至相关的成员函数。我们来看下loki::socpeguard是怎么实现的:
先看下基本的用法
(1) FILE* hFileOpen = fopen(....);
(2) LOKI_ON_BLOCK_EXIT(flose,hFileOpen);
line2会在出LOKI_ON_BLOCK_EXIT域或E序异常l束时被调用Q下面是对类成员的调?br />void CTestObject::Create
{
LOKI_ON_BLOCK_EXIT_OBJ(*this,FressResouce);
...
}
同上面差不多Q会在这个函数结束后或异常结束后调用cL员的FreeResource.在正常流E结束后Q可以通过调用Dismiss来防止对FreeResouce的调用,即类似数据库操作的commit操作。下面来分析下LOKI的实玎ͼ
从上面可以看刎ͼRAII的是Q?br />1Q构造函数对资源的获?br />2Q稀构函数对资源的释?br />先来看下LoKi对上面那2个宏的定?br />#define LOKI_ON_BLOCK_EXIT Loki::ScopeGuard LOKI_ANONYMOUS_VARIABLE(scopeGuard) = Loki::MakeGuard
#define LOKI_ON_BLOCK_EXIT_OBJ Loki::ScopeGuard LOKI_ANONYMOUS_VARIABLE(scopeGuard) = Loki::MakeObjGuard
上面的Loki::ScopeGuard是一个基cȝ别名
typedef const ScopeGuardImplBase& ScopeGuard;
而LOKI_ANONYMOUS_VARIABLE(scopeGuard)用来我们产生唯一的名字,有时假如需要调用Dismiss的话Q则需要自己去实现宏定义的内容Q这h能通过对象讉K。Loki::MakeGuard或Loki::MakeObjGuard是用来生对象的实际cd的,下面是一?br />Loki::MakeGuard的例子:
template <typename F, typename P1>
inline ScopeGuardImpl1<F, P1> MakeGuard(F fun, P1 p1)
{
return ScopeGuardImpl1<F, P1>::MakeGuard(fun, p1);
}
可以看到ScopeGuardImpl1<F, P1>是要产生的具体类型,MakeGuard通过函数参数的数目来重蝲的,而MakeGuard此处的作用是要睡M...-_-'',作用是利用函数自动推导出参数的类型,q样免M指定ScopeGuardImpl1的类型的ȝQ?br />ScopeGuardImpl1<F, P1>::MakeGuard(fun, p1);
单的q回对象的一个时变量,qassignl一个上面的一个scopeguard的实例,q里依赖一个C++的特性,临时变量的声命周期和通过他初始化的引用类型的声明周期是一致的?/p>
从上面可以看到Loki定义了一个ScopeGuardImplBase的基cR这个类定义了一个基本的ҎDismiss,以及相关的状态。下面是loki中这个类的定?br />class ScopeGuardImplBase
{
ScopeGuardImplBase& operator =(const ScopeGuardImplBase&);
protected:
~ScopeGuardImplBase()
{}
ScopeGuardImplBase(const ScopeGuardImplBase& other) throw()
: dismissed_(other.dismissed_)
{
other.Dismiss();
}
template <typename J>
static void SafeExecute(J& j) throw()
{
if (!j.dismissed_)
try
{
j.Execute();
}
catch(...)
{}
}
mutable bool dismissed_;
public:
ScopeGuardImplBase() throw() : dismissed_(false)
{}
void Dismiss() const throw()
{
dismissed_ = true;
}
};
可以看到c里面定义了上面所说的一些属性,其中SafeExecute用来提供子类同一的资源释放方法,q调用子cȝҎ来具体操作,因ؓ相关的函敎ͼ变量都保存在具体的子c,可以看到q个函数使用了try catchQ这里加q个的目的是Q因源释放要在子cȝE构里被触发,而调用具体的Ҏ是外面传q来的,所以无法保证一定是异常安全的,而假如在E构里面异常的话,会导致程序的行ؓ无法定义?br />下面具体来看下一个子cȝ实现Q?br />template <typename F, typename P1>
class ScopeGuardImpl1 : public ScopeGuardImplBase
{
public:
static ScopeGuardImpl1<F, P1> MakeGuard(F fun, P1 p1)
{
return ScopeGuardImpl1<F, P1>(fun, p1);
}
~ScopeGuardImpl1() throw()
{
SafeExecute(*this);
}
void Execute()
{
fun_(p1_);
}
protected:
ScopeGuardImpl1(F fun, P1 p1) : fun_(fun), p1_(p1)
{}
F fun_;
const P1 p1_;
};
在LoKi里面可以看到很多cMScopeGuardImpl1的定义,比如ScopeGuardImpl0Q?br />ScopeGuardImpl2Q可以发现最后面的数字表C具体参数的数目?br />可以看到上面所说的MakeGuard的定义,以及对基cL法的调用Q可以看到构造函数接收的cdQ一个函数对象,和一些参数对象,q保存,对于成员函数的scopeguard,LoKi定义?些相似的c,主要是增加了对象的引用,q有是函数的调用方式上?br />上面可以看到参数是通过值的方式来保存的而不是通过引用。而且是const属性的Q下面是相关的分析?br />1Q通过传值的方式Q从而避免了异常抛出Ӟ可能引用的对象被E?br />2Q加const属性,从而保证了在func需要参数是reference时而保存的参数是非const时生相应的~译错误Q因为对reference传hconst non-reference形式是错误的?br />而对?的方式,存在的一U问题是假如操作的fun需要传入引用,那传q去的值就无法在释攄函数中被改变Q?是对q种的一U类似契U似的编E,Loki 提供的方法是通过一个中间对象来保存操作参数的引用,q赋予这个对象自动{换功能。下面是q个cȝ定义Q?br />template <class T>
class RefToValue
{
public:
RefToValue(T& ref) : ref_(ref)
{}
RefToValue(const RefToValue& rhs) : ref_(rhs.ref_)
{}
operator T& () const
{
return ref_;
}
private:
// Disable - not implemented
RefToValue();
RefToValue& operator=(const RefToValue&);
T& ref_;
};
可以很清楚的看到cȝ实现Q下面是一个工L
template <class T>
inline RefToValue<T> ByRef(T& t)
{
return RefToValue<T>(t);
}
下面l个具体的例子,假如
template<typename _Ty>
void SAFEDELETE(_Ty*& ptr)
{
if (NULL != ptr)
delete ptr;
ptr = NULL;
}
char* ptr = new char;
{
LOKI_ON_BLOCK_EXIT(SAFEDELETE<char>,Loki::ByRef(ptr));
}
if (NULL == ptr)
std::cout << "NULL" << std::endl;
基本上就q么多了QsleepM
alex_yuu
template<typename _typelist>
class any
{
public:
typedef typename Loki::TL::TypeAtNonStrict<_typelist,0>::Result param1;
typedef typename Loki::TL::TypeAtNonStrict<_typelist,1>::Result param2;
typedef typename Loki::TL::TypeAtNonStrict<_typelist,2>::Result param3;
typedef typename Loki::TL::TypeAtNonStrict<_typelist,3>::Result param4;
typedef typename Loki::TL::TypeAtNonStrict<_typelist,4>::Result param5;
any(param1 param):
m_param1(param){}
any(param2 param):
m_param2(param){}
any(param3 param):
m_param3(param){}
any(param4 param):
m_param4(param){}
template<typename _Ty>
const _Ty& Get()
{
class CERROR_ACCESS_DENIED;
LOKI_STATIC_CHECK((Loki::TL::IndexOf<_typelist,_Ty>::value != - 1),CERROR_ACCESS_DENIED);
return __Access<_Ty>();
}
private:
template<typename _Ty>
_Ty& __Access();
template<>
param1& __Access<param1>() {return m_param1;}
template<>
param2& __Access<param2>() {return m_param2;}
template<>
param3& __Access<param3>() {return m_param3;}
template<>
param4& __Access<param4>() {return m_param4;}
param1 m_param1;
param2 m_param2;
param3 m_param3;
param4 m_param4;
};
typedef any<Loki::TYPE_LIST_3(int,float,char)> ANY;
time - task
图中头指向的方向表C紧q度的添?那么下面是关?,2,3,4的定?
一:d比较重要,但相应的旉也很?/p>
?d是长期Q?但比较重?/p>
?不那么重要的d,旉也很?/p>
?不需要多长时间的非重要Q?/p>
现在分析下上面的q些:
对于一:往往q个时候处于时间的dead line状?而此时往往是我们都不想要的,熟话说事情是急不来的,q个时候往往会导致质量的下降.
对于?我们有充的旉来做重要的Q?q正是我们想要的,?怎么做才能其不会过渡到区间一?转ؓ区间1往往会由于h的惰性生的,关键是要提前做事.安排好时?
对于?往往是一些可以辅助我们成长的事情,q些东西Ҏ们有益处,q对全面的发展vC很好的作?-_-''p我学吉他..
对于?是些旉?但不重要的Q?比如要帮助h去google一些资?
从上面可以看?区间一实际上是最差的,但ؓ了做好区?,我们必须要尽量减区?的䆾?而对于全面的发展,我们也要安排旉到区?.q也是很重要?
class IScrollWindow
{
public:
virtual void DrawScroll(void) = 0;
};
class IListWindow
{
public:
virtual void DrawList(void) = 0;
};
class ICreateWindowFactory
{
public:
virtual IScrollWindow* CreateScrollWindow(void) = 0;
virtual IListWindow* CreateListWindow(void) = 0;
};
class CBlueWindowFactory:
public ICreateWindowFactory
{
class CBlueScrollWindow:
public IScrollWindow
{
public:
virtual void DrawScroll(void)
{
std::cout << "draw blue scroll" << std::endl;
}
};
class CBlueListWindow:
public IListWindow
{
public:
virtual void DrawList(void)
{
std::cout << "draw blue list" << std::endl;
}
};
public:
virtual IScrollWindow* CreateScrollWindow(void)
{
return new CBlueScrollWindow;
}
virtual IListWindow* CreateListWindow(void)
{
return new CBlueListWindow;
}
};
class CRedWindowFactory:
public ICreateWindowFactory
{
class CRedScrollWindow:
public IScrollWindow
{
public:
virtual void DrawScroll(void)
{
std::cout << "draw red scroll" << std::endl;
}
};
class CRedListWindow:
public IListWindow
{
public:
virtual void DrawList(void)
{
std::cout << "draw red list" << std::endl;
}
};
public:
virtual IScrollWindow* CreateScrollWindow(void)
{
return new CRedScrollWindow;
}
virtual IListWindow* CreateListWindow(void)
{
return new CRedListWindow;
}
};
在需要用的地方,可以这P
ICreateWindowFactory* pCreateWindow1 = new CBlueWindowFactory;
pCreateWindow1->CreateListWindow()->DrawList();
pCreateWindow1->CreateScrollWindow()->DrawScroll();
假如需要用不同的工厂,则更换不会媄响到调用处的代码。因为掉用工厂的地方是面向接口的。其实abstract factory的理念应该是比较单的(^^瞎猜?.基本讲完了什么是抽象cd厂,他要解决的一些问题以及怎么解决?个小而ؕ的demo代码Dc下面来看下我们怎么泛化q个cd厂,q个会涉及到loki里面的具体实玎ͼ大家要加满a啊,因ؓ泛化cd厂是一件不Ҏ的事情啊?/p>
泛化_1
首先Q?^^q部分我也不是很?要泛化的是abstract factory的接口,p上面的CreateScrollWindow和CreateListWindowQ在泛化旉要的信息是要创徏的同1l对象的相关接口比如IScrollBar,IList{等Q在loki里面Q要?个类泛化1l接口,可以通过GenScatterHierarchy来将unit应用到typelist里的?个类型,q将该类从unit<type>zQ从而得?l接口。GenScatterHierarchy做了什么呢Q他产生了啥呢?具体的可以看morden c++里面的实现。通过GenScatterHierarchy我们得到了我们要?l接口。下面是loki里面对这个得相关实现
template <class T>
class AbstractFactoryUnit
{
public:
virtual T* DoCreate(Type2Type<T>) = 0;
virtual ~AbstractFactoryUnit() {}
};
可以看到Q上面定义了2个函敎ͼ而这个类是我上面说得调用GenScatterHierarchyӞL化时对typelist得每个类型应用得templatec,而最后生得也将是类?font color="#0000ff">AbstractFactoryUnit<IScrollBar>的类Q?/font>我们具体的抽象工厂从q些z。至于pure dctorq个大家应该都知道啥作用。下面来看Abstract Factory 的泛化:
template
<
class TList,
template <class> class Unit = AbstractFactoryUnit
>
class AbstractFactory : public GenScatterHierarchy<TList, Unit>
{
public:
typedef TList ProductList;
template <class T> T* Create()
{
Unit<T>& unit = *this;
return unit.DoCreate(Type2Type<T>());
}
};
可以看到q个即由GenScatterHierarchy来得C我们惌的东ѝ提供了Create的模板函敎ͼ使得我们可以象这样factory.Create<IScrollBar>()的方便Ş势来调用。ProductList是对于抽象工厂要创徏的类型的重命名。方便后面在产生实际的类型时Q获取对应的cd信息Q对于DoCreate的参敎ͼ大家应该都明白这是重载用的,那用在哪里呢Q下面会介绍?/font>
q个cL供了寚w?的解冟뀂下面会讲解Q主要的ҎQ对象不同于指针Q对象能传递const属性?br />下面看下pimlT的定义:
template<class T, template<class> class Ptr = ConstPropPtr>
struct PimplT
{
typedef T Impl;
// declare pimpl
typedef Pimpl<ImplT<T>, Ptr<ImplT<T> > > Type;
// inherit pimpl
typedef PimplOwner<ImplT<T>, Ptr<ImplT<T> > > Owner;
};
可以看到?/font>Type
的定义,下面的owner也不说了Q直接到Pimpl,
template
<
class T,
typename Pointer = ConstPropPtr<T>
>
class Pimpl
{
public:
typedef T Impl;
Pimpl() : ptr_(new T)
{}
~Pimpl()
{
typedef char T_must_be_defined[sizeof(T) ? 1 : -1 ];
}
T* operator->()
{
return ptr_.operator->();
}
T& operator*()
{
return ptr_.operator*();
}
const T* operator->() const
{
return ptr_.operator->();
}
const T& operator*() const
{
return ptr_.operator*();
}
Pointer& wrapped()
{
return ptr_;
}
const Pointer& wrapped() const
{
return ptr_;
}
private:
Pimpl(const Pimpl&);
Pimpl& operator=(const Pimpl&);
Pointer ptr_;
};