STL源码解析之vector自实现
最近仔细阅读了下侯捷老师的《STL源码剖析》的前三章内容:空间配置器、迭代器、traits技术,为了加强理解和掌握,特参照源码自实现Vector,以下对相关重点知识进行说明。
1. vector实现框架
2. 空间配置器
空间配置器方面的内容在之前的博客已进行详细说明,查看->STL空间配置器解析和实现.
3. 内存基本处理工具
(1)对象构造
(2)Destroy()函数的泛化和特化版本实现,主要体现对象T是否包含trivial construct
(3)迭代器范围赋值
(4)迭代器范围拷贝
template<class T1, class T2>
void Construct(T1* p, const T2& value)
{
new (p) T1(value); // placement new;调用T1::T1(value)
} template<class T>
void Destroy(T* p)
{
p->~T();
p = NULL;
} template<class ForwardIterator>
void Destroy(ForwardIterator first, ForwardIterator last)
{
ForwardIterator iter = first;
while (iter != last)
{
typedef typename TRAITS_DEFINE::iterator_traits<ForwardIterator>::value_type T;
cout << typeid(T).name();
T p = (T)*iter;
Destroy(&p);
iter++;
}
} template<class ForwardIterator>
void Destroy(ForwardIterator first, ForwardIterator last, TRAITS_DEFINE::__true_type)
{
;
} template<class ForwardIterator>
void Destroy(ForwardIterator first, ForwardIterator last, TRAITS_DEFINE::__false_type)
{
for (; first<last; first++)
{
Destroy(&*first)
}
} template<class ForwardIterator, class T>
void Destroy(ForwardIterator first, ForwardIterator last, T*)
{
typedef typename TRAITS_DEFINE::__type_traits<T>::has_trivial_destructor trivial_destructor;
Destroy(first, last, trivial_destructor());
}
template<class OutputIterator>
OutputIterator uninitialized_fill_n_ex(OutputIterator iter, const size_type& nSize, const T& nValue)
{
for (size_t i = ; i < nSize; i++)
{
*iter++ = nValue;
} return iter;
} void Fill_Initialize(const size_type& nSize, const T& nValue)
{
Iterator iter = data_allocator::Allocate(nSize);
uninitialized_fill_n_ex(iter, nSize, nValue); Start = iter;
Finish = Start + nSize;
EndOfStorage = Finish;
} template<class InputIterator, class OutputIterator>
OutputIterator uninitialzed_copy_ex(InputIterator first, InputIterator last, OutputIterator dest)
{
for (; first != last; first++,dest++)
{
*dest = *first;
} return dest;
}
4. iterator_traites和type_traits
类型萃取实现的关键计数在于“模版特例化”,通过class template partial specialization的作用,不论是原生指针或class-type iterators,都可以让外界方便地取其相应类别
原生指针不是class type,如果不是class type就无法为它定义内嵌型别。但模板特例化解决了该问题
template<class T>
class C{...}; // 这个泛化版本允许(接受)T为任何型别
template<class T>
class C<T*>{...}; // 这个特化版本仅适用于“T为原生指针”的情况
type_traits类型萃取,判断T类型中是否含有trivial construct,这样在destroy函数的就可以根据其做相应的处理
namespace TRAITS_DEFINE
{
template<class T>
struct iterator_traits
{
typedef T value_type;
}; template<class T>
struct iterator_traits<T *>
{
typedef T value_type;
}; struct __true_type{};
struct __false_type{};
template<class type>
struct __type_traits
{
typedef __true_type this_dummy_must_be_first;
typedef __false_type has_trivial_default_constructor;
typedef __false_type has_trivial_copy_constructor;
typedef __false_type has_trivial_assignment_operator;
typedef __false_type has_trivial_destructor;
typedef __false_type is_POD_type;
}; template<>
struct __type_traits<int>
{
typedef __true_type this_dummy_must_be_first;
typedef __true_type has_trivial_default_constructor;
typedef __true_type has_trivial_copy_constructor;
typedef __true_type has_trivial_assignment_operator;
typedef __true_type has_trivial_destructor;
typedef __true_type is_POD_type;
};
}
5. vector代码实现
5.1. 构造
typedef T& Reference;
typedef T* Iterator;
typedef T value_type;
typedef size_t size_type;
typedef CSimpleAlloc<value_type> data_allocator; // 自定义空间配置器 Iterator Start;
Iterator Finish;
Iterator EndOfStorage;
Vector():Start(NULL), Finish(NULL),EndOfStorage(NULL){
cout << "Vector()" << endl;
}
Vector(const size_type& nSize, const T& nValue)
{
Fill_Initialize(nSize, nValue);
}
explicit Vector(const size_type& nSize)
{
Fill_Initialize(nSize, T());
}
void Fill_Initialize(const size_type& nSize, const T& nValue)
{
Iterator iter = data_allocator::Allocate(nSize);
uninitialized_fill_n_ex(iter, nSize, nValue); Start = iter;
Finish = Start + nSize;
EndOfStorage = Finish;
}
5.2. 析构
void Deallocate()
{
if (Start)
{
data_allocator::Deallocate(Start, EndOfStorage-Start);
}
}
~Vector()
{
Destroy(Start, Finish);
Deallocate();
}
5.3. Push
void Push(const T& Value)
{
if (Finish != EndOfStorage)
{
Construct(Finish, Value); // 全局函数
++Finish;
}
else
{
// 容器已满,需扩容
Insert_Aux(End(), Value);
}
}
void Insert_Aux(Iterator position, const T& value)
{
if (Finish != EndOfStorage)
{
// 还有备用空间可用
Construct(Finish, *(Finish - ));
++Finish;
T x_copy = value;
//copy_backward(position, Finish - 2, Finish - 1);
*position = x_copy;
}
else
{
// 已无备用空间
size_type nOldSize = Size();
size_type nNewSize = (nOldSize == ) ? : * nOldSize;
Iterator NewStart = data_allocator::Allocate(nNewSize);
Iterator NewFinish = NewStart;
try
{
NewFinish = uninitialzed_copy_ex(Start, position, NewStart);
Construct(NewFinish, value);
NewFinish++;
}
catch (...)
{
Destroy(NewStart, NewFinish);
data_allocator::Deallocate(NewStart, nNewSize);
throw;
} Destroy(Begin(),End());
data_allocator::Deallocate(Start, EndOfStorage - Start); Start = NewStart;
Finish = NewFinish;
EndOfStorage = Start + nNewSize;
}
}
5.4. Pop_Back
void Pop_Back()
{
if (!Empty())
{
--Finish;
Destroy(Finish);
}
}
5.5. Erase
Erase方法只能清空元素,但不能释放空间
Iterator Erase(Iterator pos)
{
if (pos + != Finish)
{
copy(pos + , Finish, pos);
}
--Finish;
destroy(Finish);
return pos;
}
Iterator Erase(Iterator first, Iterator last)
{
Iterator iter = uninitialzed_copy_ex(last, Finish, first);
Destroy(iter, Finish);
Finish = Finish - (last - first);
return first;
}
5.6. Resize
void Resize(size_type new_size, const T& x) {
//如果新空间大小 小于size 就裁去多余的 如果新空间大于size那么就将这些插入.
if (new_size < Size())
Erase(Begin() + new_size, End());
else
{
Iterator NewStart = data_allocator::Allocate(new_size);
Iterator NewFinish = NewStart;
try
{
NewFinish = uninitialzed_copy_ex(Start, Finish, NewStart);
for (size_t i = ; i < (new_size-Size()); i++)
{
*NewFinish++ = x; }
}
catch (...)
{
Destroy(NewStart, NewFinish);
data_allocator::Deallocate(NewStart, new_size);
throw;
} Destroy(Begin(), End());
data_allocator::Deallocate(Start, EndOfStorage - Start); Start = NewStart;
Finish = NewFinish;
EndOfStorage = Start + new_size;
}
}
5.7. 全部实现
#pragma once
#include "simple_alloc.h"
#include <iostream>
#include<memory>
using namespace std; /*
Construct和Destroy实现
*/
namespace TRAITS_DEFINE
{
template<class T>
struct iterator_traits
{
typedef T value_type;
}; template<class T>
struct iterator_traits<T *>
{
typedef T value_type;
}; struct __true_type{};
struct __false_type{};
template<class type>
struct __type_traits
{
typedef __true_type this_dummy_must_be_first;
typedef __false_type has_trivial_default_constructor;
typedef __false_type has_trivial_copy_constructor;
typedef __false_type has_trivial_assignment_operator;
typedef __false_type has_trivial_destructor;
typedef __false_type is_POD_type;
}; template<>
struct __type_traits<int>
{
typedef __true_type this_dummy_must_be_first;
typedef __true_type has_trivial_default_constructor;
typedef __true_type has_trivial_copy_constructor;
typedef __true_type has_trivial_assignment_operator;
typedef __true_type has_trivial_destructor;
typedef __true_type is_POD_type;
};
} // 内存管理工具
template<class T1, class T2>
void Construct(T1* p, const T2& value)
{
new (p) T1(value); // placement new;调用T1::T1(value)
} template<class T>
void Destroy(T* p)
{
p->~T();
p = NULL;
} template<class ForwardIterator>
void Destroy(ForwardIterator first, ForwardIterator last)
{
ForwardIterator iter = first;
while (iter != last)
{
typedef typename TRAITS_DEFINE::iterator_traits<ForwardIterator>::value_type T;
cout << typeid(T).name();
T p = (T)*iter;
Destroy(&p);
iter++;
}
} template<class ForwardIterator>
void Destroy(ForwardIterator first, ForwardIterator last, TRAITS_DEFINE::__true_type)
{
;
} template<class ForwardIterator>
void Destroy(ForwardIterator first, ForwardIterator last, TRAITS_DEFINE::__false_type)
{
for (; first<last; first++)
{
Destroy(&*first)
}
} template<class ForwardIterator, class T>
void Destroy(ForwardIterator first, ForwardIterator last, T*)
{
typedef typename TRAITS_DEFINE::__type_traits<T>::has_trivial_destructor trivial_destructor;
Destroy(first, last, trivial_destructor());
} /*
* 实现vector
* vector基本操作:构造、resize、erase、push、pop
*/
template <typename T>
class Vector
{
public:
typedef T& Reference;
typedef T* Iterator;
typedef T value_type;
typedef size_t size_type;
typedef CSimpleAlloc<value_type> data_allocator; // 自定义空间配置器 Iterator Start;
Iterator Finish;
Iterator EndOfStorage; public:
Vector():Start(NULL), Finish(NULL),EndOfStorage(NULL){
cout << "Vector()" << endl;
}
Vector(const size_type& nSize, const T& nValue)
{
Fill_Initialize(nSize, nValue);
}
explicit Vector(const size_type& nSize)
{
Fill_Initialize(nSize, T());
}
~Vector()
{
Destroy(Start, Finish);
Deallocate();
}
Iterator Begin(){return Start;}
Iterator End(){return Finish;}
size_type Size() const { return size_type(Finish - Start); }
size_type Capacity() const { return size_type(EndOfStorage - Start); }
bool Empty() { return Begin() == End(); }
Reference operator[](const size_type& nIndex)
{
return *(start + n);
} Reference Front(){ return *Start; }
Reference Back(){ return *(--Finish); } void Push(const T& Value)
{
if (Finish != EndOfStorage)
{
Construct(Finish, Value); // 全局函数
++Finish;
}
else
{
// 容器已满,需扩容
Insert_Aux(End(), Value);
} }
void Pop_Back()
{
if (!Empty())
{
--Finish;
Destroy(Finish);
}
} void Print()
{
cout << "打印vector所有元素: ";
Iterator iter = Start;
while (iter != Finish)
{
cout << *iter << " ";
iter++;
}
cout << endl;
} Iterator Erase(Iterator pos)
{
if (pos + != Finish)
{
copy(pos + , Finish, pos);
}
--Finish;
destroy(Finish);
return pos;
}
Iterator Erase(Iterator first, Iterator last)
{
Iterator iter = uninitialzed_copy_ex(last, Finish, first);
Destroy(iter, Finish);
Finish = Finish - (last - first);
return first;
} void Resize(size_type new_size, const T& x) {
//如果新空间大小 小于size 就裁去多余的 如果新空间大于size那么就将这些插入.
if (new_size < Size())
Erase(Begin() + new_size, End());
else
{
Iterator NewStart = data_allocator::Allocate(new_size);
Iterator NewFinish = NewStart;
try
{
NewFinish = uninitialzed_copy_ex(Start, Finish, NewStart);
for (size_t i = ; i < (new_size-Size()); i++)
{
*NewFinish++ = x; }
}
catch (...)
{
Destroy(NewStart, NewFinish);
data_allocator::Deallocate(NewStart, new_size);
throw;
} Destroy(Begin(), End());
data_allocator::Deallocate(Start, EndOfStorage - Start); Start = NewStart;
Finish = NewFinish;
EndOfStorage = Start + new_size;
}
} void Clear()
{
Erase(Start, Finish);
}
private: void Deallocate()
{
if (Start)
{
data_allocator::Deallocate(Start, EndOfStorage-Start);
}
}
void Insert_Aux(Iterator position, const T& value)
{
if (Finish != EndOfStorage)
{
// 还有备用空间可用
Construct(Finish, *(Finish - ));
++Finish;
T x_copy = value;
//copy_backward(position, Finish - 2, Finish - 1);
*position = x_copy;
}
else
{
// 已无备用空间
size_type nOldSize = Size();
size_type nNewSize = (nOldSize == ) ? : * nOldSize;
Iterator NewStart = data_allocator::Allocate(nNewSize);
Iterator NewFinish = NewStart;
try
{
NewFinish = uninitialzed_copy_ex(Start, position, NewStart);
Construct(NewFinish, value);
NewFinish++;
}
catch (...)
{
Destroy(NewStart, NewFinish);
data_allocator::Deallocate(NewStart, nNewSize);
throw;
} Destroy(Begin(),End());
data_allocator::Deallocate(Start, EndOfStorage - Start); Start = NewStart;
Finish = NewFinish;
EndOfStorage = Start + nNewSize;
}
} // 申请并填充内存
template<class OutputIterator>
OutputIterator uninitialized_fill_n_ex(OutputIterator iter, const size_type& nSize, const T& nValue)
{
for (size_t i = ; i < nSize; i++)
{
*iter++ = nValue;
} return iter;
} void Fill_Initialize(const size_type& nSize, const T& nValue)
{
Iterator iter = data_allocator::Allocate(nSize);
uninitialized_fill_n_ex(iter, nSize, nValue); Start = iter;
Finish = Start + nSize;
EndOfStorage = Finish;
} template<class InputIterator, class OutputIterator>
OutputIterator uninitialzed_copy_ex(InputIterator first, InputIterator last, OutputIterator dest)
{
for (; first != last; first++,dest++)
{
*dest = *first;
} return dest;
}
};
vector_define.h
// 完全解析STL空间配置器
/***** 一级配置区 ****************************/
// 1. 采用mallo/relloc/free申请和释放内存
// 2. 处理内存申请失败的处理
// (1)设置set_new_handle,若为NULL抛出__THROW_BAD_ALLOC;
// (2)尝试重复申请
/**********************************************/
#pragma once class CFirstLevelAlloc;
class CSecondLevelAlloc; #ifdef _CHUNK_ALLOC
typedef CFirstLevelAlloc SelfAlloc;
#else
typedef CSecondLevelAlloc SelfAlloc;
#endif typedef void(*CallBackFunc)();
class CFirstLevelAlloc
{
public:
CFirstLevelAlloc(); static CallBackFunc m_CallBackFunc;
static void* Allocate(size_t nSize);
static void* Allocate(void *p, size_t nSize);
static void Deallocate(void *p, size_t nSize = );
static void SetCallBackHandle(CallBackFunc cb); private:
static void* ReAllocate(size_t nSize);
static void* ReAllocate(void *p, size_t nSize);
}; enum {ALIGN = }; // 小型区块的上调边界
enum {MAX_BYTES = }; // 小型区块的上限
enum {FREELISTNUM = MAX_BYTES/ALIGN}; // free-lists个数 // 空闲内存链表结构
union FreeList
{
union FreeList *pFreeList;
char client_data[];
}; class CSecondLevelAlloc
{
public:
CSecondLevelAlloc();
static void* Allocate(size_t nSize);
static void Deallocate(void *p, size_t nSize);
static void SetCallBackHandle(CallBackFunc cb); private:
static size_t FreeListIndex(int nBytes); // 根据区块大小得到freelist索引
static size_t Round_Up(int nBytes); // 将bytes按内存对齐上调至ALIGN的倍数
static char *ChunkAlloc(size_t nSize, int& nObjs);
static void* Refill(size_t nSize); private:
static FreeList *m_pFreeList[FREELISTNUM];
static char *m_pStartFree;
static char *m_pEndFree;
static size_t m_nHeapSize;
};
alloc_define.h
#pragma once #include "alloc_define.h"
template<typename T, typename Alloc = SelfAlloc>
class CSimpleAlloc
{
public:
static T* Allocate(size_t n)
{
if (n == )
{
return NULL;
}
return (T *)Alloc::Allocate(n * sizeof(T));
} static T* Allocate(void)
{
return (T *)Alloc::Allocate(sizeof(T));
} static void Deallocate(T *p, size_t n)
{
if (n != )
{
Alloc::Deallocate(p, n * sizeof(T));
}
} static void Deallocate(T *p)
{
Alloc::Deallocate(p, sizeof(T));
} static void SetCallBackHandle(CallBackFunc cb)
{
Alloc::SetCallBackHandle(cb);
}
};
simple_alloc.h
5.8. 测试
#include "stdio.h" #include "vector_define.h" #include<vector>
using namespace std; void main()
{
cout << "Vector(const size_type& nSize, const T& nValue)测试:" << endl;
Vector<int> vect1(, );
vect1.Print(); cout << "Vector()--Push()--Pop测试:" << endl;
Vector<int> vect2;
vect2.Push();
vect2.Push();
vect2.Push();
vect2.Push();
vect2.Print();
vect2.Pop_Back();
vect2.Print(); cout << "Iterator Erase(Iterator first, Iterator last)测试:" << endl;
Vector<int>::Iterator iter1 = vect2.Begin();
Vector<int>::Iterator iter2 = vect2.End();
vect2.Erase(iter1, iter2);
cout << "vect Size:" << vect2.Size() << endl; cout << "void Resize(size_type new_size, const T& x)测试:" << endl;
vect2.Resize(, );
vect2.Print();
vect2.Resize(, );
vect2.Print();
}
STL源码解析之vector自实现的更多相关文章
- Java集合类源码解析:Vector
[学习笔记]转载 Java集合类源码解析:Vector 引言 之前的文章我们学习了一个集合类 ArrayList,今天讲它的一个兄弟 Vector.为什么说是它兄弟呢?因为从容器的构造来说,Vec ...
- stl源码分析之vector
上篇简单介绍了gcc4.8提供的几种allocator的实现方法和作用,这是所有stl组件的基础,容器必须通过allocator申请分配内存和释放内存,至于底层是直接分配释放内存还是使用内存池等方法就 ...
- 《STL源码剖析》——Vector
vector vector的源码分为多个文件:vector.<<stl_vector.h>> vector的底层实现是在<<stl_vector.h>> ...
- STL源码剖析-vector
STL(Standard Template Library) C++标准模板库,acm选手一定对它不陌生,除了算法,那几乎是“吃饭的家伙了”.我们使用库函数非常方便,且非常高效(相对于自己实现来说). ...
- vector源码3(参考STL源码--侯捷):pop_back、erase、clear、insert
vector源码1(参考STL源码--侯捷) vector源码2(参考STL源码--侯捷):空间分配.push_back vector源码(参考STL源码--侯捷)-----空间分配导致迭代器失效 v ...
- vector源码(参考STL源码--侯捷):空间分配导致迭代器失效
vector源码1(参考STL源码--侯捷) vector源码2(参考STL源码--侯捷) vector源码(参考STL源码--侯捷)-----空间分配导致迭代器失效 vector源码3(参考STL源 ...
- vector源码2(参考STL源码--侯捷):空间分配、push_back
vector源码1(参考STL源码--侯捷) vector源码2(参考STL源码--侯捷) vector源码(参考STL源码--侯捷)-----空间分配导致迭代器失效 vector源码3(参考STL源 ...
- vector源码1(参考STL源码--侯捷):源码
vector源码1(参考STL源码--侯捷) vector源码2(参考STL源码--侯捷) vector源码(参考STL源码--侯捷)-----空间分配导致迭代器失效 vector源码3(参考STL源 ...
- Java 集合系列06之 Vector详细介绍(源码解析)和使用示例
概要 学完ArrayList和LinkedList之后,我们接着学习Vector.学习方式还是和之前一样,先对Vector有个整体认识,然后再学习它的源码:最后再通过实例来学会使用它.第1部分 Vec ...
随机推荐
- CSS3自定义滚动条样式 之 -webkit-scrollbar
有没有觉得浏览器自带的原始滚动条很不美观,同时也有看到很多网站的自定义滚动条显得高端,就连chrome32.0开发板都抛弃了原始的滚动条,美观多了.那webkit浏览器是如何自定义滚动条的呢? 前言 ...
- Javascript 中 == 与=== 对比
首先,== equality 等同,=== identity 恒等. ==, 两边值类型不同的时候,要先进行类型转换,再比较. ===,不做类型转换,类型不同的一定不等. 下面分别说明: 先说 === ...
- 优秀 H5 案例收集 vol.1(不定期更新)
一生要历经的三种战斗http://datang.wearewer.com/ 雍正去哪儿http://news.163.com/college/special/craftsman_h5/ 比Emoji更 ...
- Python3.x: pyodbc+FreeTDS+UinxODBC连接sybase数据库(Linux系统)
Python3.x: pyodbc+FreeTDS+UinxODBC连接sybase数据库(Linux系统) 一.安装UinxODBC以及依赖包 yum -y install gcc gcc-c++ ...
- Windows:FTP命令大全
Windows:FTP命令大全 简介 1, open:与服务器相连接: 2, send(put):上传文件: 3,get:下载文件: 4,mget:下载多个文件: 用法: mget *:下载当前路径下 ...
- [pixhawk笔记]3-架构概览
本文主要内容翻译自:https://dev.px4.io/en/concept/architecture.html 总体架构: PX4代码由两层组成:PX4飞行栈和PX4中间件.其中,前者是一套飞行控 ...
- Unix下 五种 I/O模型
Unix下共有五种I/O模型: 1. 阻塞式I/O 2. 非阻塞式I/O 3. I/O复用(select和poll) 4. 信号驱动式I/O(SIGIO) 5. 异步I/O(POSIX的aio ...
- tar 解压命令学习与总结
tar -c: 建立压缩档案 -x:解压 -t:查看内容 -r:向压缩归档文件末尾追加文件 -u:更新原压缩包中的文件 这五个是独立的命令,压缩解压都要用到其中一个,可以和别的命令连用但只能用其中一个 ...
- JNI_Z_08_创建Java对象
1.步骤 : (1).获取 jclass (2).获取 构造函数的 method id (方法的名称始终为"<init>") (3).创建Java对象的两种方式: (3 ...
- phpexcel: 数据导出
// 设置列名最多40个 $cols = array( "A", "B", "C", "D", "E" ...