读书人

Allocator类模板的奇怪定义(codeproj

发布时间: 2012-02-26 20:19:44 作者: rapoo

Allocator类模板的奇怪定义(codeproject的代码),如下:
//Policy driven allocator object
template <typename T, typename Policy = StandardAllocPolicy <T> , typename Traits = ObjectTraits <T> >
class Allocator : public Policy, public Traits {
private :
typedef Policy AllocationPolicy;
typedef Traits TTraits;

public : // 这里的重定义是必要的吗?
typedef typename AllocationPolicy::size_type size_type;
typedef typename AllocationPolicy::difference_type difference_type;
typedef typename AllocationPolicy::pointer pointer;
typedef typename AllocationPolicy::const_pointer const_pointer;
typedef typename AllocationPolicy::reference reference;
typedef typename AllocationPolicy::const_reference const_reference;
typedef typename AllocationPolicy::value_type value_type;

public :
template <typename U>
struct rebind {
typedef Allocator <U, typename AllocationPolicy::rebind <U> ::other> other;
};

public :
inline explicit Allocator() {}
inline ~Allocator() {}
inline Allocator(Allocator const& rhs):Traits(rhs), Policy(rhs) {}
template <typename U>
inline explicit Allocator(Allocator <U> const&) {}
template <typename U, typename P, typename T2>
inline Allocator(Allocator <U, P, T2> const& rhs):Traits(rhs), Policy(rhs) {}

//memory allocation
//这里allocate、deallocate是不是重复了,可以删除吗?
inline pointer allocate(size_type cnt, typename std::allocator <void> ::const_pointer hint = 0) {
return AllocationPolicy::allocate(cnt, hint);
}
inline void deallocate(pointer p, size_type cnt) {
AllocationPolicy::deallocate(p, cnt);
}
};//end of class Allocator

[解决办法]
模板在编译的时候,名字搜索规则是很复杂的。
前面的type重复,是为了避免误用外部空间里的类型定义。
后面一个去掉则问题不大。

有很多语法细节/编程风格的问题,不要钻得太深入。
[解决办法]
在一个模板中为一些类型参数起别名(typedef)已经是C++的习惯了。有什么用呢?看下面的代码:
//一个范型算法,通过交换两个容器的元素
template <class C1, class C2>
exch(C1& cnt1, C2& cnt2) {
??? temp; //这里该用什么类型声明呢?
??? begin1, end1;//还有这里?
??? begin2; //以及这里?
for(; begin1!=end1; ++begin1, ++begin2)
{
temp=*begin1;
*begin1=*begin2;
*begin2=temp;
}
}
由于在编写这个函数模板时我们不知道容器中元素的类型,以及容器的类型,那么,temp的类型也就无从确定了。但是,由于在容器中都声明了一些辅助类型,所以,我们的范型算法才得以实现:
template <class C1, class C2>
exch(C1& cnt1, C2& cnt2) {
C1::value_type temp; //容器通过类型别名给出了容器元素的类型
C1::iterator begin1, end1;//容器通过类型别名给出了迭代器的类型
C2::iterator begin2; // 同上
...
}
从上面的例子中,可以看出,类型别名typedef在范型编程中起到非常重要的作用,尽管他们乍看是没有必要的。推广到一般的模板组件,typedef将模板的使用者同模板的具体实现,在类型上隔离了。用户只需关心模板中某个类型的逻辑含义,而无需关心实际类型。此时,模板便可以对类型进行充分地泛化。
实际上这些typedef是模板接口的一部分。通过这种手段,可以使代码充分泛化,达到最高效编程的目的。


反过来,我们也可以认为,如果一种语言不能为类型取别名,那么可以断定这种语言无法实现真正的范型编程。
[解决办法]
继然是多重继承

你怎么不想想第二基类Traits中也是不是有那些类型呢

如果有,当然那些typedef是必要的


这个Allocator显然只是一个包装的类,成员函数都是对Policy成员函数的转调用

Allocator只是一个符合某种规范的壳,真正的操作由传给Policy的类来完成,这里提供了灵活性。
[解决办法]
是这样的,typedef typename AllocationPolicy::size_type size_type; 定义了Allocator::size。因为Allocator继承了Policy和Traits,而这两个类是可以由用户定义的。它们都可能定义了size_type等等。如果不做typedef,那么就潜藏着两个基类不能同时定义size_type等类型的规则,否则在使用Allocator时就有可能发生歧义。这种潜规则会加大编程复杂度,与设计Allocator的初衷背道而驰。因此,这个定义是必要的。
而且,首先定义AllocationPolicy,再用它定义Allocator::size_type等,可以方便今后的修改,提高可伸缩性。
allocator,deallocator则是编程语义明确性的考量。Allocator必须提供allocator和deallocator的接口。而这些接口将借助Policy的同名接口改变其行为。虽然目前的Allocator使用的是同一方式借助Policy的同名接口,但就Allocator和Policy的语义而言,同一方式不是必须的。因此,明确定义这两个接口,就是表达了“将来可能不采用同一方式”这一诉求。
虽然从实现上而言,由于Allocator继承了Policy,因而目前这两个接口是不必要的(注意按Traits的语义,它绝对不应该定义allocator和deallocator接口,和上面第一个问题不同,因此不会有二义性的发生)。但是这里的继承是一种实现手段,而非一般意义上的is-a关系,所以从语义角度不应该省略它们。在因为基类和派生类中,它们有着不同的语义。

读书人网 >C++

热点推荐