热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

关于c++:STLvector内部实现原理及基本用法

1.vector类的实现重要构造定义:{代码}供类外部以及派生类应用:{代码}{代码}{代码}{代码}{代码}{代码}供内部应用的接口:{代码}{代码}{代码}{代码}push_back函数:{代码}insert函数:{代码}{代码}2.自定义函数{代码}3.测试代码{代码}{代码}

1.vector类的实现

重要构造定义:

template
class myVector{
public:
    typedef T value_type;//元素类型  起别名
    typedef value_type* pointer;//
    typedef value_type* iterator;//迭代器
    typedef value_type& reference;//援用
    typedef const value_type* const_pointer;//常量指针
    typedef const value_type& const_reference;//常量援用
    typedef size_t size_type;//数据类型根本尺寸大小
private:
    iterator start;
    iterator finish;
    iterator end_of_storage;

供类外部以及派生类应用:

protected:
//调配空间并填充初始值, 不返回任何值
void __allocate_add_fill(size_type n, const T& value){
        iterator result = (iterator)malloc(n*sizeof(T));
        if (result){//result!=0  申请内存胜利,在失去的内存上创建对象
            start = result;
            end_of_storage = start + n;
            finish = end_of_storage;
            while (n--){
                //指针偏移,进行赋值
                construct(result, value);//在内存上,一个个的进行结构对象
                ++result;
            }
        }
        else{
            cout <<"内存不足,程序终止!" <
//调配空间 从first开始复制n个值到新空间中, 并返回新开拓的空间的首地址
    iterator __allocate_and_copy(iterator first, size_type n){
        //内存申请
        iterator result = (iterator)malloc(n*sizeof(T));
        iterator _start = result;
        if (0 != result){
            while(n--){
                construct(result, *first);
                ++result;
                ++first;
            }
            cout <
//将first到last迭代器之间(first,last)的元素拷贝到_start开始的内存中, 并返回 指向 拷贝完所有数据之后最初一个数据的下一个地位的指针
    iterator __copy(iterator first, iterator last, iterator _start){
        while (first 
//将first到last迭代器之间(first,last)的元素从新赋值
iterator __fill(iterator first, iterator last, const T& value){
    while (first 
//本人写的 从迭代器first开始填充n个值为value的元素
iterator __fill_n(iterator first, size_type n, const T& value){
    while (n--){
        *first++ = value;
    }
    return first;
}
//本人写的  将从 [first,last)所有元素 一一顺次后移, 最初的一个元素移到end的地位
void __backCopy(iterator first, iterator last, iterator end){
    while (last >= first){ //
        *end-- = *last--;
    }
}

供内部应用的接口:

public:
    //返回首元素指针
    iterator begin(){ return start; }
    const iterator begin() const { return start; }

    //返回尾元素下一个地位的指针
    iterator end(){ return finish; }
    const iterator end() const{ return finish; }

    //------------------
    //取元素  本人写
    T front(){ return *begin(); }//取vector中第一个元素
    T back(){ return *(end() - 1); }//取vector中最初一个元素

    //容器大小
    size_type size() const{ return (size_type)(end() - begin()); }

    //容器的理论大小
    size_type capacity() const{ return (end_of_storage - begin()); }

    //判断容器是否为空
    bool empty(){ return begin() == end(); }
//默认构造函数
    myVector() :start(NULL), finish(NULL), end_of_storage(NULL){ cout <<"默认构造函数,不调配空间" <
//元素操作
    //删除最初一个元素
    void pop_back(){
        if (!empty()){
            --finish;
            destroy(finish);
        }
    }

    //删除指定地位上的元素,并返回指向删除元素的迭代器
    iterator erase(iterator position){
        if (position > begin() && position 
//删除指定范畴的元素  并返回 迭代器返回的元素
    iterator erase(iterator first, iterator last){
        if (first > begin() && first 

push_back函数:

//在vector容器的前面增加一个元素,值为value
    void push_back(const T& value){
        if (finish != end_of_storage){//如果新退出元素后,空间够用的话
            construct(finish, value);
            ++finish;
        }
        else{//如果新退出元素之后 空间不够用的话
            //重新分配空间
            const size_type old_size = size();
            const size_type new_size = (old_size == 0) ? 1 : 2 * old_size;//如果原空间为0,则配置1的大小,如果原空间不为0,则配置原空间二倍大小的新空间到新的地址
            iterator new_start = (iterator)malloc(new_size*sizeof(T));
            iterator new_finish = new_start;//开始时,未拷贝前,完结地位等于起始地位
            iterator new_capacity = new_start + new_size;

            //内存调配要具备原子性,即: 要么全副胜利,要么全副失败
            try{//1:将原空间的全副元素拷贝到新空间 2:为新的元素设定初始值 3:调整 new_finish
                for (iterator it = begin(); it 

insert函数:

//插入 在值为value的一个元素到position的地位上
    void insert(iterator position, const T& value){
        insert(position, 1, value);
    }

    //在position地位之后,插入n的值为value的元素
    void insert(iterator position, size_type n, const T& value){
        if (n == 0)return;

        if ((end_of_storage - finish) >= n){//备用空间够插入n个新元素
            T x_copy = value;
            const  size_type size_from_position_to_end = finish - position;

            iterator old_finish = finish;
            if (size_from_position_to_end > n){
                //先从pos到oldfinish拿出后n个数,放到前面
                //再将pos到剩下的几个数向后挪动到oldfinish
                //插入n个value到pos->pos+n
                __copy(finish - n, finish, finish);
                finish += n;
                __backCopy(position, old_finish - n, old_finish);
                __fill(position, position + n, x_copy);
            }
            else{
                //在前面先插入多的value,而后再将pos到oldfinish的拿进去插到前面
                //而后将剩下的value放到pos到oldfinsh
                __fill_n(finish, n - size_from_position_to_end, x_copy);
                finish += n - size_from_position_to_end;
                __copy(position, old_finish, finish);
                finish += size_from_position_to_end;
                __fill(position, old_finish, x_copy);//在
            }
        }
        else{
            //从新申请空间
            const size_type old_size = size();
            size_type _max = 0;
            if (old_size > n) _max = old_size;
            else _max = n;
            const size_type len = old_size + _max;
            iterator new_start = (iterator)malloc(len * sizeof(T));
            iterator new_finish = new_start;
            //内存的调配要有原子性,即:要么全副胜利,要么全副失败。
            try{
                new_finish = __copy(begin(), position, new_start);//1.将原内容 至position的所有元素(不蕴含position) 拷贝到新的vector
                new_finish = __fill_n(new_finish, n, value);//2.将position地位到前面的n个元素都填充为value
                new_finish = __copy(position, end(), new_finish);//3.拷贝从 position地位到end()地位的原vector的所有残余元素
            }
            catch (...)//如果失败了
            {
                destroy(new_start, new_finish);
                free(new_start);//删除申请到的内存
                new_start = new_finish = NULL;
                throw;        //抛出异样
            }
            //析构并开释原vector
            destroy(begin(), end());
            //删除内存
            free(start);
            //调整迭代器,指向新的vector
            start = new_start;
            finish = new_finish;
            end_of_storage = new_start + len;
        }
    }
//重载操作符
    reference operator[](size_type n){ return *(begin() + n); }//取 第n个元素
    const_reference operator[](size_type n) const{ return *(begin() + n); }

    //两个容器是否相等(每个元素)
    bool operator==(const myVector&v){
        if (v.size() != size())return false;
        iterator it;
        for (it = v.begin(); it 

2.自定义函数

#pragma once

template
inline void construct(T1 *p, const T2 &value){
    new (p)T1(value);      //用placement new在所指对象上创立一个对象,value是初始化对象的值
}

template
inline void destroy(T* pointer){//只做了一层包装,将指针所指的对象析构--通过间接调用类的析构函数
    pointer->~T();
}

template
inline void destroy(ForwardIterator first, ForwardIterator last){//destroy的泛化版 承受两个迭代器为参数
    for (; first 

3.测试代码

void display(const myVector &v){
    for (myVector::iterator it = v.begin(); it != v.end(); ++it){
        cout <<*it <<" ";
    }
    cout < v(100);
    v.push_back(10);
    v.push_back(9);
    v.push_back(8);
    v.push_back(7);
    v.push_back(6);
    v.push_back(5);
    for (int i = 0; i ::iterator it;
    for (it = v.begin(); it != v.end(); ++it){
        cout <<*it <<" ";
    }
    cout <
void test1(){
    cout <<"test1--------" < v(100);
    v.push_back(10);
    v.push_back(9);
    v.push_back(8);
    v.push_back(7);
    v.push_back(6);
    v.push_back(5);

    myVector::iterator it = v.begin() + 3;

    v.insert(it, 3, 300); display(v);
    v.insert(it, 4, 500); display(v);
    v.insert(it, 2, 200); display(v);
    v.insert(it, 2, 20); display(v);
    v.insert(it, 3, 30); display(v);
    v.insert(it, 4, 40); display(v);
}
void test2(){
    cout <<"test2--------" < v(100);
    v.push_back(10);
    v.push_back(9);
    v.push_back(8);
    v.push_back(7);
    v.push_back(6);
    v.push_back(5);

    myVector::iterator it = v.begin();

    v.insert(it, 300); display(v);
    v.insert(it, 500); display(v);
    v.insert(it, 200); display(v);
    v.insert(it, 20); display(v);
    v.insert(it, 30); display(v);
    v.insert(it, 40); display(v);
}

运行后果:

/*
test--------
10 9 8 7 6 5 
10 9 8 7 6 5 
size: 6
test1--------
10 9 8 300 300 300 7 6 5 
10 9 8 500 500 500 500 300 300 300 7 6 5 
10 9 8 200 200 500 500 500 500 300 300 300 7 6 5 
10 9 8 20 20 200 200 500 500 500 500 300 300 300 7 6 5 
10 9 8 30 30 30 20 20 200 200 500 500 500 500 300 300 300 7 6 5 
10 9 8 40 40 40 40 30 30 30 20 20 200 200 500 500 500 500 300 300 300 7 6 5 
test2--------
300 10 9 8 7 6 5 
500 300 10 9 8 7 6 5 
200 500 300 10 9 8 7 6 5 
20 200 500 300 10 9 8 7 6 5 
30 20 200 500 300 10 9 8 7 6 5 
40 30 20 200 500 300 10 9 8 7 6 5 
Program ended with exit code: 0
*/

援用:https://github.com/MissStrick&#8230;


推荐阅读
  • 海马s5近光灯能否直接更换为H7?
    本文主要介绍了海马s5车型的近光灯是否可以直接更换为H7灯泡,并提供了完整的教程下载地址。此外,还详细讲解了DSP功能函数中的数据拷贝、数据填充和浮点数转换为定点数的相关内容。 ... [详细]
  • 本文介绍了Java的集合及其实现类,包括数据结构、抽象类和具体实现类的关系,详细介绍了List接口及其实现类ArrayList的基本操作和特点。文章通过提供相关参考文档和链接,帮助读者更好地理解和使用Java的集合类。 ... [详细]
  • 本文介绍了如何使用PHP向系统日历中添加事件的方法,通过使用PHP技术可以实现自动添加事件的功能,从而实现全局通知系统和迅速记录工具的自动化。同时还提到了系统exchange自带的日历具有同步感的特点,以及使用web技术实现自动添加事件的优势。 ... [详细]
  • 在Docker中,将主机目录挂载到容器中作为volume使用时,常常会遇到文件权限问题。这是因为容器内外的UID不同所导致的。本文介绍了解决这个问题的方法,包括使用gosu和suexec工具以及在Dockerfile中配置volume的权限。通过这些方法,可以避免在使用Docker时出现无写权限的情况。 ... [详细]
  • 本文介绍了在Python3中如何使用选择文件对话框的格式打开和保存图片的方法。通过使用tkinter库中的filedialog模块的asksaveasfilename和askopenfilename函数,可以方便地选择要打开或保存的图片文件,并进行相关操作。具体的代码示例和操作步骤也被提供。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 本文详细说明了在JavaScript中解决alert弹出窗口文本换行问题的方法。通过给alert弹出的文本添加换行符,可以实现在弹窗中显示多行文本的效果。同时,提供了相关代码示例和注意事项,帮助读者更好地理解和应用这一解决方法。 ... [详细]
  • Day2列表、字典、集合操作详解
    本文详细介绍了列表、字典、集合的操作方法,包括定义列表、访问列表元素、字符串操作、字典操作、集合操作、文件操作、字符编码与转码等内容。内容详实,适合初学者参考。 ... [详细]
  • 在Oracle11g以前版本中的的DataGuard物理备用数据库,可以以只读的方式打开数据库,但此时MediaRecovery利用日志进行数据同步的过 ... [详细]
  • C语言常量与变量的深入理解及其影响
    本文深入讲解了C语言中常量与变量的概念及其深入实质,强调了对常量和变量的理解对于学习指针等后续内容的重要性。详细介绍了常量的分类和特点,以及变量的定义和分类。同时指出了常量和变量在程序中的作用及其对内存空间的影响,类似于const关键字的只读属性。此外,还提及了常量和变量在实际应用中可能出现的问题,如段错误和野指针。 ... [详细]
  • 本文介绍了一种图片处理应用,通过固定容器来实现缩略图的功能。该方法可以实现等比例缩略、扩容填充和裁剪等操作。详细的实现步骤和代码示例在正文中给出。 ... [详细]
  • 手把手教你使用GraphPad Prism和Excel绘制回归分析结果的森林图
    本文介绍了使用GraphPad Prism和Excel绘制回归分析结果的森林图的方法。通过展示森林图,可以更加直观地将回归分析结果可视化。GraphPad Prism是一款专门为医学专业人士设计的绘图软件,同时也兼顾统计分析的功能,操作便捷,可以帮助科研人员轻松绘制出高质量的专业图形。文章以一篇发表在JACC杂志上的研究为例,利用其中的多因素回归分析结果来绘制森林图。通过本文的指导,读者可以学会如何使用GraphPad Prism和Excel绘制回归分析结果的森林图。 ... [详细]
author-avatar
可爱的你公馆_698
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有