侯捷先生在《漫谈程序员与编程》 中讲到 STL 运用的三个档次:“会用 STL,是一种档次。对 STL 原理有所了解,又是一个档次。追踪过 STL 源码,又是一个档次。第三种档次的人用起 STL 来,虎虎生风之势绝非第一档次的人能够望其项背。”
看完EASTL回过头来,我认为STL也就这样,不必抱有畏难的心理,掌握基本的C++编程即可开始了解STL。
每隔几个月常读常新,循序渐进,要是能在工作中追踪过STL源码并解决问题,那就最好不过了。
作为一个干净简单的起点,去入手STL源码,为阅读EASTL打下基础
实际看了,会发现也并没有很难,比起阅读《C++标准库》这样的砖头API书籍,要更为容易和高效
不必完整读完,差不多就可以直接去EASTL了
整体实现还是有一些简陋了,缺乏细节
重点分析了vector的内存使用方法,其他线性表结构其实都是差不多的(stack,queue,string),不必重复看
然后是pair和智能指针,并没有什么难度
以后应该不会再看了
从单元测试开始看起
TinySTL\Detail\Vector.impl.h(55): error C2572: ‘TinySTL::vector
::resize’: redefinition of default argument: parameter 1
默认参数只能定义一次,这里是一个模板函数拆分了声明和实现,在实现处也加了默认参数
没有include
,self-contained问题
STL也有的容器,和TinySTL做相同的操作,然后比较容器相等即可
有点鸭子类型的味道
template<class Container1, class Container2>
static inline bool container_equal(const Container1 &pair1, const Container2 &pair2) {
return (pair1.first == pair2.first && pair1.second == pair2.second);
}
为模板起别名
template<typename T>
using stdPair = std::pair<T, T>;
template<typename T>
using tsPair = TinySTL::pair<T, T>;
...
stdPair<int> p1(5, 5);
tsPair<int> p2(5, 5);
swap T,是指两个T互换数据,不是first和second互换
这是一个类型递归概念,每个类型都需要实现swap语义
具体代码没什么难的
template<class T>
void swap(T &a, T &b) {
T temp = a;
a = b;
b = temp;
}
template<class T1, class T2>
struct pair {
void swap(pair &pr);
template<class T1, class T2>
friend void swap(pair<T1, T2> &x, pair<T1, T2> &y);
}
template<class T1, class T2>
void pair<T1, T2>::swap(pair<T1, T2> &pr) {
TinySTL::swap(first, pr.first);
TinySTL::swap(second, pr.second);
}
template<class T1, class T2>
void swap(pair<T1, T2> &x, pair<T1, T2> &y) {
x.swap(y);
}
...
foo.swap(bar);
TODO EASTL比这复杂得多,move
template<class T1, class T2>
struct pair {
public:
typedef T1 first_type;
typedef T2 second_type;
public:
T1 first;
T2 second;
public:
pair() {}
template<class U, class V>
pair(const pair<U, V> &pr);
pair(const first_type &a, const second_type &b);
pair &operator=(const pair &pr);
}
重载比较运算符,运算符被标记为friend,可以访问private成员
template<class T1, class T2>
struct pair {
public:
template<class T1, class T2>
friend bool operator==(const pair<T1, T2> &lhs, const pair<T1, T2> &rhs);
template<class T1, class T2>
friend bool operator!=(const pair<T1, T2> &lhs, const pair<T1, T2> &rhs);
template<class T1, class T2>
friend bool operator<(const pair<T1, T2> &lhs, const pair<T1, T2> &rhs);
template<class T1, class T2>
friend bool operator<=(const pair<T1, T2> &lhs, const pair<T1, T2> &rhs);
template<class T1, class T2>
friend bool operator>(const pair<T1, T2> &lhs, const pair<T1, T2> &rhs);
template<class T1, class T2>
friend bool operator>=(const pair<T1, T2> &lhs, const pair<T1, T2> &rhs);
template<class T1, class T2>
friend void swap(pair<T1, T2> &x, pair<T1, T2> &y);
};
...
assert(!(foo == bar));
assert(foo != bar);
assert(foo < bar);
assert(!(foo > bar));
assert(foo <= bar);
assert(!(foo >= bar));
在ctor上套了一层
存储三个指针
EASTL的构造会写的比较晦涩,重点关注内存分配,分离new的malloc和调用ctor两个操作
template<class T, class Alloc = allocator<T>>
class vector{
private:
T *start_;
T *finish_;
T *endOfStorage_;
typedef Alloc dataAllocator;
public:
typedef T value_type;
typedef T* iterator;
//typedef const iterator const_iterator;
typedef const T* const_iterator;
typedef reverse_iterator_t<T*> reverse_iterator;
typedef reverse_iterator_t<const T*> const_reverse_iterator;
typedef iterator pointer;
typedef T& reference;
typedef const T& const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
public:
//构造,复制,析构相关函数
vector()
:start_(0), finish_(0), endOfStorage_(0){}
explicit vector(const size_type n);
vector(const size_type n, const value_type& value);
template<class InputIterator>
vector(InputIterator first, InputIterator last);
vector(const vector& v);
vector(vector&& v);
vector& operator = (const vector& v);
vector& operator = (vector&& v);
~vector();
}
T()
调用默认构造函数template<class T, class Alloc>
vector<T, Alloc>::~vector(){
destroyAndDeallocateAll();
}
template<class T, class Alloc>
vector<T, Alloc>::vector(const size_type n){
allocateAndFillN(n, value_type());
}
template<class T, class Alloc>
vector<T, Alloc>::vector(const size_type n, const value_type& value){
allocateAndFillN(n, value);
}
template<class T, class Alloc>
template<class InputIterator>
vector<T, Alloc>::vector(InputIterator first, InputIterator last){
//处理指针和数字间的区别的函数
vector_aux(first, last, typename std::is_integral<InputIterator>::type());
}
template<class T, class Alloc>
vector<T, Alloc>::vector(const vector& v){
allocateAndCopy(v.start_, v.finish_);
}
template<class T, class Alloc>
vector<T, Alloc>::vector(vector&& v){
start_ = v.start_;
finish_ = v.finish_;
endOfStorage_ = v.endOfStorage_;
v.start_ = v.finish_ = v.endOfStorage_ = 0;
}
template<class T, class Alloc>
vector<T, Alloc>& vector<T, Alloc>::operator = (const vector& v){
if (this != &v){
allocateAndCopy(v.start_, v.finish_);
}
return *this;
}
template<class T, class Alloc>
vector<T, Alloc>& vector<T, Alloc>::operator = (vector&& v){
if (this != &v){
destroyAndDeallocateAll();
start_ = v.start_;
finish_ = v.finish_;
endOfStorage_ = v.endOfStorage_;
v.start_ = v.finish_ = v.endOfStorage_ = 0;
}
return *this;
}
tsVec temp2(10, 0);
填充temp2,10个0
堆栈如下,跑了一些模板type_traits,关键是先用Alloc分配内存,然后*first = value;
调用拷贝构造
template<class T, class Alloc>
void vector<T, Alloc>::allocateAndFillN(const size_type n, const value_type& value){
start_ = dataAllocator::allocate(n);
TinySTL::uninitialized_fill_n(start_, n, value);
finish_ = endOfStorage_ = start_ + n;
}
template<class ForwardIterator, class Size, class T>
inline ForwardIterator uninitialized_fill_n(ForwardIterator first,
Size n, const T& x){
typedef typename _type_traits<T>::is_POD_type isPODType;
return _uninitialized_fill_n_aux(first, n, x, isPODType());
}
template<class ForwardIterator, class Size, class T>
ForwardIterator _uninitialized_fill_n_aux(ForwardIterator first,
Size n, const T& x, _true_type){
return fill_n(first, n, x);
}
template<class OutputIterator, class Size, class T>
OutputIterator fill_n(OutputIterator first, Size n, const T& value)
{
for (; n > 0; --n, ++first)
*first = value;
return first;
}
tsVec v2(10, "zxh");
同样的接口,string不是POD,走placement_new
这里封装了一下placement_new,更加清晰
template<class ForwardIterator, class Size, class T>
ForwardIterator _uninitialized_fill_n_aux(ForwardIterator first,
Size n, const T& x, _false_type){
int i = 0;
for (; i != n; ++i){
construct((T*)(first + i), x);
}
return (first + i);
}
封装new和delete,以及array版本,所以是四个函数
template<class T1, class T2>
inline void construct(T1 *ptr1, const T2& value){
new(ptr1) T1(value);
}
template<class T>
inline void destroy(T *ptr){
ptr->~T();
}
template<class ForwardIterator>
inline void _destroy(ForwardIterator first, ForwardIterator last, _true_type){}
template<class ForwardIterator>
inline void _destroy(ForwardIterator first, ForwardIterator last, _false_type){
for (; first != last; ++first){
destroy(&*first);
}
}
template<class ForwardIterator>
inline void destroy(ForwardIterator first, ForwardIterator last){
typedef typename _type_traits<ForwardIterator>::is_POD_type is_POD_type;
_destroy(first, last, is_POD_type());
}
tsVec v6(std::begin(arr), std::end(arr));
可以理解为拷贝一个容器的一部分
NOTE InputIterator要区分一下是否是指针,和函数resolve有关
template<class T, class Alloc>
template<class InputIterator>
vector<T, Alloc>::vector(InputIterator first, InputIterator last){
//处理指针和数字间的区别的函数
vector_aux(first, last, typename std::is_integral<InputIterator>::type());
}
template<class T, class Alloc>
template<class InputIterator>
void vector<T, Alloc>::allocateAndCopy(InputIterator first, InputIterator last){
start_ = dataAllocator::allocate(last - first);
finish_ = TinySTL::uninitialized_copy(first, last, start_);
endOfStorage_ = finish_;
}
template<class T, class Alloc>
vector<T, Alloc>::vector(vector&& v){
start_ = v.start_;
finish_ = v.finish_;
endOfStorage_ = v.endOfStorage_;
v.start_ = v.finish_ = v.endOfStorage_ = 0;
}
template<class T, class Alloc>
void vector<T, Alloc>::push_back(const value_type& value){
insert(end(), value);
}
在索引n处插入若干item
分两步:
第一步可能触发扩容,直接重新分配一大块内存依次填充数据
? 这里怎么是placement new,应该是拷贝构造
template<class T, class Alloc>
template<class Integer>
void vector<T, Alloc>::insert_aux(iterator position, Integer n, const value_type& value, std::true_type){
assert(n != 0);
difference_type locationLeft = endOfStorage_ - finish_; // the size of left storage
difference_type locationNeed = n;
if (locationLeft >= locationNeed){
auto tempPtr = end() - 1;
for (; tempPtr - position >= 0; --tempPtr){//move the [position, finish_) back
//*(tempPtr + locationNeed) = *tempPtr;//bug
construct(tempPtr + locationNeed, *tempPtr);
}
TinySTL::uninitialized_fill_n(position, n, value);
finish_ += locationNeed;
}
else{
reallocateAndFillN(position, n, value);
}
}
insert的逆向操作,但是不会触发扩容
直接调用拷贝构造,T自己去处理相关释放
template<class T, class Alloc>
typename vector<T, Alloc>::iterator vector<T, Alloc>::erase(iterator first, iterator last){
//尾部残留对象数
difference_type lenOfTail = end() - last;
//删去的对象数目
difference_type lenOfRemoved = last - first;
finish_ = finish_ - lenOfRemoved;
for (; lenOfTail != 0; --lenOfTail){
auto temp = (last - lenOfRemoved);
*temp = *(last++);
}
return (first);
}
简单的指针。。
typedef T value_type;
typedef T* iterator;
//typedef const iterator const_iterator;
typedef const T* const_iterator;
typedef reverse_iterator_t<T*> reverse_iterator;
typedef reverse_iterator_t<const T*> const_reverse_iterator;
//迭代器相关
iterator begin(){ return (start_); }
const_iterator begin()const{ return (start_); }
const_iterator cbegin()const{ return (start_); }
iterator end(){ return (finish_); }
const_iterator end()const{ return (finish_); }
const_iterator cend()const{ return (finish_); }
reverse_iterator rbegin(){ return reverse_iterator(finish_); }
const_reverse_iterator crbegin()const{ return const_reverse_iterator(finish_); }
reverse_iterator rend(){ return reverse_iterator(start_); }
const_reverse_iterator crend()const{ return const_reverse_iterator(start_); }
//与容量相关
difference_type size()const{ return finish_ - start_; }
difference_type capacity()const{ return endOfStorage_ - start_; }
bool empty()const{ return start_ == finish_; }
void resize(size_type n, value_type val = value_type());
void reserve(size_type n);
void shrink_to_fit();
vector维护了三个指针,将n与size和capacity进行比较,分三种情况讨论:
reserve就是扩容,略
template<class T, class Alloc>
void vector<T, Alloc>::resize(size_type n, value_type val){
if (n < size()){
dataAllocator::destroy(start_ + n, finish_);
finish_ = start_ + n;
}
else if (n > size() && n <= capacity()){
auto lengthOfInsert = n - size();
finish_ = TinySTL::uninitialized_fill_n(finish_, lengthOfInsert, val);
}
else if (n > capacity()){
auto lengthOfInsert = n - size();
T *newStart = dataAllocator::allocate(getNewCapacity(lengthOfInsert));
T *newFinish = TinySTL::uninitialized_copy(begin(), end(), newStart);
newFinish = TinySTL::uninitialized_fill_n(newFinish, lengthOfInsert, val);
destroyAndDeallocateAll();
start_ = newStart;
finish_ = newFinish;
endOfStorage_ = start_ + n;
}
}
template<class T, class Alloc>
void vector<T, Alloc>::reserve(size_type n){
if (n <= capacity())
return;
T *newStart = dataAllocator::allocate(n);
T *newFinish = TinySTL::uninitialized_copy(begin(), end(), newStart);
destroyAndDeallocateAll();
start_ = newStart;
finish_ = newFinish;
endOfStorage_ = start_ + n;
}
vector
,维护三个指针这块还是看其他库把
class string{
public:
//npos is a static member constant value with the greatest possible value for an element of type size_t.
static const size_t npos = -1;
private:
char *start_;
char *finish_;
char *endOfStorage_;
typedef TinySTL::allocator<char> dataAllocator;
public:
string() :start_(0), finish_(0), endOfStorage_(0){}
string(const string& str);
string(string&& str);
string(const string& str, size_t pos, size_t len = npos);
string(const char* s);
string(const char* s, size_t n);
string(size_t n, char c);
template <class InputIterator>
string(InputIterator first, InputIterator last);
string& operator= (const string& str);
string& operator= (string&& str);
string& operator= (const char* s);
string& operator= (char c);
~string();
}