定义自己的STL容器 (1)

如何借助STL开发自己的容器?

STL(Standard Template Library, 标准模板库)使用容器(Container)、迭代器(Iterator)、算法(Algorithm)构建了一个强大的框架,它允许我们使用STL中的容器存储任何类型的数据,并通过迭代器来存取,或者是调用STL中的算法。那么如何设计自己的模板,使之可以借助STL的算法以达到某些便捷的效果?

设计分配器

借助allocator<T>来设计容器存储的数据类型,其中value_type即为容器中所存储的数据的类型。分配器(Allocator)负责为模板分配空间,释放空间。在此,我们不使用封装技术设计自定义的Allocator类,而是直接为模板分配空间,STL模板库在底层使用类似的方法为模板分配空间。


typedef typename allocator<T>::value_type value_type;
typedef typename allocator<T>::size_type size_type;

void
init_space(size_type size){ begin_ = (iter)::operator new(size*sizeof(value_type)); end_ = begin_+size; }

迭代器

typedef value_type* iter;

迭代器实际上是value_type类型指针。

数据成员

由于设计简易vector不涉及容量方面的操作,故一个首部迭代器和一个尾部迭代器便足够。

iter begin_;
iter end_;

成员函数

主要实现以下几个函数:构造函数、插入、删除、判空、获取元素个数、[]重载。

需要注意的是 insert() 与 erase() 函数:

void insert(iter ins_iter, size_type&& value){//以右值插入为例
    uninitialized_copy(ins_iter, end_, ins_iter+1);//用以将 [插入位置,结束位置) 的值复制到 [插入位置+1,新的结束位置)
    *ins_iter = move(value); //将 插入位置 的值更新为待插入值 value
    ++end_; //由于只插入了一个值,将尾部迭代器++即可,插入多个值的情况可依此设计
}
void erase(iter ers_iter){
        assert(ers_iter < end_ && ers_iter >= begin_);
        uninitialized_copy(ers_iter+1, end_, ers_iter);//将 [删除位置+1,结束位置) 的值复制给 [删除位置,结束位置-1)
        (end_-1)->~T();//注意:此处一定要使用泛型的析构函数
        --end_;//由于只删除了一个元素,末尾迭代器--即可,删除多个元素可依照此设计
}

完整实现

头文件:demo.h

#ifndef Demo_H
#define Demo_H

#include <memory>
#include <iterator>
#include <cassert>

using namespace std;

template<typename T>
class Demo{
public:
    typedef typename allocator<T>::value_type value_type;
    typedef typename allocator<T>::size_type size_type;

    typedef value_type* iter;

public:
    
    //构造函数
    Demo() {
    }

    //以空间n构造
    Demo(size_type n){
        init_space(n);
        uninitialized_fill(n, value_type());
    }

    //以n个实值构造
    Demo(size_type n, const value_type& value){
        init_space(n);
        uninitialized_fill_n(begin_, n, value);
    }

    //拷贝构造函数
    Demo(const Demo& demo){
        init_space(static_cast<size_type>(demo.end_ - demo.begin_));
        uninitialized_copy(demo.begin_, demo.end_, begin_);
    }

    //操作符重载
    const value_type& operator[](size_type idx) const{
        assert(idx < size());
        return *(begin_+idx);
    }

    value_type& operator[](size_type idx){
        assert(idx < size());
        return *(begin_+idx);
    }

    
    //增删改查
    void insert(iter ins_iter, const size_type& value){
        insert(ins_iter, value);
    }

    void insert(iter ins_iter, size_type&& value){
        uninitialized_copy(ins_iter, end_, ins_iter+1);
        *ins_iter = move(value);
        ++end_;
    }
    
    void erase(iter ers_iter){
        assert(ers_iter < end_ && ers_iter >= begin_);
        uninitialized_copy(ers_iter+1, end_, ers_iter);
        (end_-1)->~T();
        --end_;
    }
    

    //基础部分
    bool empty(){
        return begin_ == end_;
    }
    
    size_type size(){
        return static_cast<size_type>(end_ - begin_);
    }
    
    iter begin(){
        return begin_;
    }
    
    iter end(){
        return end_;
    }


private:

    iter begin_;
    iter end_;
    
    //不对外用于内部调用公开的方法
    void init_space(size_type size){
        begin_ = (iter)::operator new(size*sizeof(value_type));
        end_ = begin_+size;
    }
};

#endif //Demo_H

测试

源文件:main.cpp

#include <iostream>
#include "demo.h"
#include <algorithm>

int main() {
    using namespace std;

    Demo<int> demo(10, 1024);

    cout<<"---------size()----------
";
    cout<<demo.size()<<endl;

    cout<<"---------end()----------
";
    cout<<*(demo.end()-1)<<endl;

    cout<<"---------迭代器----------
";
    for(auto it = demo.begin();it != demo.end();++it){
        cout<<*it << " ";
    }
    cout<<"
";

    cout<<"--------下标运算符--------
";
    for (int i = 0; i < 10; ++i) {
        cout<<demo[i]<<" ";
    }
    cout<<"
";

    demo.insert(demo.begin(), 1000);
    cout<<"---------插入----------
";
    for(auto it = demo.begin();it != demo.end();++it){
        cout<<*it << " ";
    }
    cout<<"
";

    demo.erase(demo.begin());
    cout<<"---------删除----------
";
    for(auto it = demo.begin();it != demo.end();++it){
        cout<<*it << " ";
    }
    cout<<"
";

    *(demo.begin()) = 2;*(demo.begin()+1) = 4;*(demo.begin()+2) = 8;*(demo.begin()+3) = 16;*(demo.begin()+4) = 32;*(demo.begin()+5) = 64;
    demo[6] = 128;demo[7] = 256;demo[8] = 512;demo[9] = 1024;
    cout<<"---------赋值----------
";
    for(auto it = demo.begin();it != demo.end();++it){
        cout<<*it << " ";
    }
    cout<<"
";

    sort(demo.begin(), demo.end(), greater<int>());
    cout<<"---------调用sort函数----------
";
    for(auto it = demo.begin();it != demo.end();++it){
        cout<<*it << " ";
    }
    cout<<"
";

    cout<<"---------调用max_element函数----------
";
    cout<<"max value="<<*max_element(demo.begin(), demo.end())<<endl;
    cout<<"
";

    return 0;
}

结果

---------size()----------
10
---------end()----------
1024
---------迭代器----------
1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 
--------下标运算符--------
1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 
---------插入----------
1000 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 
---------删除----------
1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 
---------赋值----------
2 4 8 16 32 64 128 256 512 1024 
---------调用sort函数----------
1024 512 256 128 64 32 16 8 4 2 
---------调用max_element函数----------
max value=1024

成功通过自定义的模板调用STL中的函数。

更进一步

这个过程中,alloctor与迭代器的设计与使用是重中之重,如何更进一步使用memory头文件中的allocator,与iterator头文件中不同种类的迭代器,是设计出更复杂更实用的容器的基石。

原文地址:https://www.cnblogs.com/icky1024/p/STL-selfSTL.html