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);
    
    
  • 相关阅读:
    BEC listen and translation exercise 44
    中译英12
    BEC listen and translation exercise 43
    中译英11
    BEC listen and translation exercise 42
    中译英10
    BEC listen and translation exercise 41
    中译英9
    BEC listen and translation exercise 40
    中译英8
  • 原文地址:https://www.cnblogs.com/ishen/p/12508379.html
Copyright © 2011-2022 走看看