山寨STL实现之traits,construct&destruct
traits技术被广泛应用于STL中,通过它您可以轻松的萃取出一个对象的特性。在STL中也是通过它来实现性能的最优化,比如一个对象是个POD对象(Plain Old Data),则在拷贝过程中直接可以通过memcpy等函数拷贝,而无需调用拷贝构造函数或operator=。
先来看看STL中最基本的对象iterator
template <typename T, typename Size = size_t, typename Difference = ptrdiff_t> struct iterator { typedef T value_type; typedef Difference difference_type; typedef T* pointer; typedef T& reference; typedef const T* const_pointer; typedef const T& const_reference; typedef iterator<T, Size, Difference> self; }; template <typename T, typename Size = size_t, typename Difference = ptrdiff_t> struct const_iterator : public iterator<T> { };
由以上代码可知,对于每一个iterator必须定义其value_type,size_type,difference_type,pointer,reference,const_pointer,const_reference和self类型。
一、value_type
value_type指示了该迭代器所保存的值类型
二、difference_type
difference_type用来指示两个迭代器之间的距离类型
三、pointer,reference,const_pointer,const_reference
分别是所指之物的指针,引用,指针常量和引用常量的类型
四、self
self为该迭代器自身的类型
下面来看一下iterator_traits,iterator_traits主要用来萃取迭代器iterator的值类型等
template <typename Iterator> struct iterator_traits { typedef typename Iterator::value_type value_type; typedef typename Iterator::difference_type difference_type; typedef typename Iterator::pointer pointer; typedef typename Iterator::reference reference; typedef typename Iterator::const_pointer const_pointer; typedef typename Iterator::const_reference const_reference; typedef typename Iterator::self self_type; };
这里有一点可以提前预告一下,vector作为一个容器,其内部是使用指针作为迭代器的,那么我们如何萃取出它的值类型等呢?
答案很简单,特例化,那么我们就来为iterator_traits分别做两种T*和const T*的特例化
template <typename T> struct iterator_traits<T*> { typedef T value_type; typedef ptrdiff_t difference_type; typedef T* pointer; typedef T& reference; typedef const T* const_pointer; typedef const T& const_reference; typedef T* self_type; }; template <typename T> struct iterator_traits<const T*> { typedef T value_type; typedef ptrdiff_t difference_type; typedef T* pointer; typedef T& reference; typedef const T* const_pointer; typedef const T& const_reference; typedef const T* self_type; };
至此,我们可以用iterator_traits萃取出每种iterator的值类型等内容了。
之前已经说到了,通过traits可以萃取出一些对象的特性,从而提高代码的效率。事实确实如此,通过traits可萃取出一个对象是否是一个POD对象,对于一个POD对象,我们在拷贝时,不应该使用其拷贝构造函数或是operator=,而用memcpy则效率更高。
下面我们来看一下__type_traits
struct __true_type { }; struct __false_type { }; template <typename T> struct __type_traits { typedef __true_type has_default_construct; typedef __true_type has_copy_construct; typedef __true_type has_assign_operator; typedef __true_type has_destruct; typedef __false_type is_POD; };
不得不提的是其中分别用__true_type和__false_type来表示是否存在这个特性。
那么我们如何萃取出基础类型诸如int,char等的特性呢?
答案依然是特例化,这里代码不再贴出,文末会给出完整代码的详细地址。
最后我们使用一个hash_destruct的函数来获取出这个类型是否有析构函数。
template <typename T> inline auto has_destruct(const T&)->decltype(static_cast<__type_traits<T>::has_destruct*>(0)) { return static_cast<typename __type_traits<T>::has_destruct*>(0); } template <typename T> inline auto has_destruct(T*)->decltype(static_cast<__type_traits<T>::has_destruct*>(0)) { static_assert(false, "Please use const T& not T*"); return static_cast<typename __type_traits<T>::has_destruct*>(0); } template <typename T> inline auto has_destruct(const T*)->decltype(static_cast<__type_traits<T>::has_destruct*>(0)) { static_assert(false, "Please use const T& not const T*"); return static_cast<typename __type_traits<T>::has_destruct*>(0); }
不得不提的是C++0x的确很强大,可以通过形参来确定返回值的类型,这样我们就可以萃取出这个类型的has_destruct域是__true_type或是__false_type了。
最后来看看construct和destruct的代码,在STL中对象的内存分配和构造是被分开的,对于基础对象int,char等,在析构时我们无需调用其析构函数。
下面来看construct和destruct的实现
template <typename T1, typename T2> inline void construct(T1* p, const T2& value) { new (p) T1(value); } template <typename T> inline void destruct(T* p, __true_type*) { p->~T(); } template <typename T> inline void destruct(T*, __false_type*) { } template <typename ForwardIterator> inline void destruct(ForwardIterator first, ForwardIterator last) { while(first != last) { destruct(&*first, has_destruct(*first)); ++first; } }
至此,关于traits技术和construct及destruct的讲解已完成,完整的代码请到http://qlanguage.codeplex.com/下载
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· [AI/GPT/综述] AI Agent的设计模式综述