zoukankan      html  css  js  c++  java
  • c++ vector详解

    1.前言

    本文mark了vector的一些接口,介绍了vector中的对内存和对象的管理详解请见cppreference-vector
    1.vector内部管理着一块内存,压入对象的时候,会使用这块内部的内存使用placement new去进行对象的生成,而释放对象的时候,显式的去调用析构函数去释放对象
    2.size代表vector中的实际含有元素数量,而capacity表示容量
    3.resize()调整size的时候会生成或释放元素,释放的本质只是调用了析构,但是那块内存块还在vector中
    4.reserve()调整capacity的时候只会增大但是不会减小
    5.push_back()同时支持copy构造&和移动语义构造&&,配合std::move或者std::forward效果更佳
    6.earse()用来删除元素,参数是迭代器, 范围删除的时候是前闭后开【 )
    7.emplace()相当于insert(),但是其通过参数包和模板偏特化减少了一次拷贝构造的过程

    2.正文

    2.1 vector基本布局

    一个简单的vector,我们可以理解成如下形式,主要是举了reserve()和resize()这两个例子,来举例vector是如何分配内存,创建初始化对象的,以及析构对象的;
    vector内部管理着一块内存,当需要push_back对象得时候,会使用这块内部的内存使用placement new去进行对象的生成,而释放对象的时候,显示的去调用析构函数去释放对象(这只是一种理解,实际实现不一定如此,但是原理上大同小异)

    template<class T>
    class vector{
        public:
            unsigned char *buffer;
            int size_;
            int capacity_;
            T value_type;
            
            //分配内存
            void reserve(int capacity){
               if(capacity > capacity_){//创建一块新内存放过去
                    unsigned char * temp = malloc(sizeof(value_type) * capacity); 
                    memcpy(temp, buffer, capacity_);
                    capacity_ = capacity;
                    free(buffer);
                    buffer = temp;
               }
            }
            
             //调整元素
            void resize(int size){
                int duration = sizeof(value_type);
                if(size > size_){
                    for(int i = size_ ; i < size ; ++i){
                        T *obj = new(buffer[i*duration])T();//使用buffer[i * duration]内存块去创建对象
                    }
                }
                else{
                    for(int i = size_ -  1; i >= size ; --i){
                        T *obj = (T*) buffer[ i* duration];
                        obj->~T();//调用析构
    
                    }
                }
            }
    };
    
    

    2.2 constructor

    • 基本构造函数
      有四种如下的方式,其中特别注意使用iterator的方式进行copy construct的时候,也可以直接传递数组地址过去,会自动转换
    // constructors used in the same order as described above:
      std::vector<int> first;                                // empty vector
      std::vector<int> second (4,100);                       // four ints with value 100
      std::vector<int> third (second.begin(),second.end());  // iterating through second
      std::vector<int> fourth (third);                       // a copy of third
    
    // the iterator constructor can also be used to construct from arrays:
      int myints[] = {16,2,77,29};
      std::vector<int> fifth (myints, myints + sizeof(myints) / sizeof(int) );
        
    
    • 列表初始化
      可以使用c++11的列表初始化进行快速初始化
    vector<int> a{{1}, {2}, {3}};    //加不加括号都一样
    vector<int> a={{1}, {2}, {3}};
    

    2.3 size()和capacity()

    size是指当前vector中含有的元素数量,capacity是指vector中拥有的空间

    • void resize (size_type n);

    调整vector的size, 如果size比当前拥有的大,会创建默认对象进行push_back,如果size比当前的小,会缩小size,但是不缩小capacity,创建和释放会调用构造函数与析构函数

    vector<int> v;
    v.resize(5);    //调整元素个数
    
    • void reserve (size_type n);

    调整vector的capacity,如果capacity比当前的小,不缩小,反之,则增加capacity

    vector<int> v;
    v.reserve(5);    //调整容量大下
    
    • value_type* data() noexcept;
      返回内存块的指针首地址
    vector<int> v(10);
    int *p = v.data(); //获取内存块首地址
    

    2.4 element access

    • reference at (size_type n);
      返回对应的位置元素的引用,和[]作用相同,但是会做检查
    vector<int> v(10);
    int number = v.at(0); //获取
    
    

    2.5 Modifiers

    • [std::vector::push_back]
      插入,参数支持引用和右值
    void push_back (const value_type& val);
    void push_back (value_type&& val);
    
      // erase the 6th element
      myvector.erase (myvector.begin()+5);
    
      // erase the first 3 elements:
      myvector.erase (myvector.begin(),myvector.begin()+3)
    
    int myints[] = {1776,7,4};
    third.assign (myints,myints+3);   // assigning from array.
    

    插入,和insert一样,但能可以减少一次copy构造, 因为参数是一个变参包,这个变参数包通过模板偏特化匹配解包,传递给对应类的构造函数直接构造对象, 我们可以这么理解参数包的运行过程:emplace将参数包传到temp中,会首先根据当前的参数找到偏特化的实现的模板 class temp, 然后调用其构造函数,此处用到了参数包+模板偏特化实现参数匹配。

    class temp{
    public:
           temp(int a, int b){
                cout<<"a:"<<a<<"b:"<<b<<endl;  // 1 2
                cout<<"construct
    ";
            }
    }
    
    template <class type>
    class vector{
        public:
        template<class ...args>
        emplace(vector<type>::Iterator iter, args ...a){
            .....
            
            //将这个参数包传给temp(int a, int b)
            temp(a...);
            .....
        }
    }
    
    vector<temp> v;
    v.emplace(v.begin(), 1,2);
    
    
  • 相关阅读:
    [CSP-S模拟测试]:party?(霍尔定理+最小割+树链剖分)
    [CSP-S模拟测试]:marshland(最大费用可行流)
    [CSP-S模拟测试]:Revive(点分治)
    [CSP-S模拟测试]:Lighthouse(哈密顿回路+容斥)
    [CSP-S模拟测试]:Lost My Music(凸包)
    [CSP-S模拟测试]:God Knows(线段树维护单调栈)
    [CSP-S模拟测试]:Star Way To Heaven(最小生成树Prim)
    [CSP-S模拟测试]:gcd(莫比乌斯反演)
    [CSP-S模拟测试]:water(BFS)
    BZOJ3462 DZY Loves Math II 【多重背包 + 组合数】
  • 原文地址:https://www.cnblogs.com/ishen/p/12508379.html
Copyright © 2011-2022 走看看