• C++ primer之动态内存管理实例


    这个我是感觉在思路上没有那么复杂啦,参考书上的提示应该能够自己写出来,就直接上代码了

    #include<iostream>
    #include<memory>
    #include<utility>
    #include<string>
    #include<algorithm>
    //Equivalent to " vector<string> "
    class StrVec{
        public:
      StrVec():elements(nullptr),frist_free(nullptr),cap(nullptr){ } 
        StrVec( const StrVec & ) ;
        StrVec( const std::initializer_list<std::string> & ) ;
        StrVec& operator=( const StrVec & ) ;
        ~StrVec() ;
        void push_back(const std::string &) ;
        size_t size() const { return frist_free - elements ;}  //元素数量
        size_t capacity() const { return cap  - elements ;}   //空间总共大小
    
        void reserve( size_t new_cap ) ;
        void resize( size_t count, const std::string &value  = std::string("666") ) ; 
    
        std::string *begin() const { return elements ;}
        std::string *end() const { return frist_free  ;}
    
        private:
        std::allocator<std::string>  alloc  ;
        void chk_n_alloc() {
            if( size() == capacity() )
                reallocate(); 
        }
        std::pair<std::string * ,std::string *> alloc_n_copy(const std::string * ,const std::string * ) ;
        void free() ;  //销毁元素并释放内存
        void reallocate(size_t temp = 1 ) ; //得到更多的内存并移动原来的元素
        std::string* elements ;
        std::string* frist_free;
        std::string* cap ;
    };
    StrVec::StrVec(const StrVec &s){
        auto newdata =  alloc_n_copy(s.begin() ,s.end() ) ;
        elements = newdata.first ;
        frist_free = cap = newdata.second ;
    }
    StrVec::StrVec( const std::initializer_list<std::string> &v ) {
        for (auto itm : v) {
            this->push_back(itm) ;
        }
    }
    StrVec& StrVec::operator=(const StrVec &s) {
        /*
         1.将右侧对象拷贝拷贝到一个局部临时对象中
        2.销毁左侧运算对象现有成员
        3.将临时局部对象拷贝到左侧运算对象的成员 
        */
        auto newdata =  alloc_n_copy(s.begin() ,s.end() ) ;
        free() ;
        elements = newdata.first ;
        frist_free = cap = newdata.second ;
        return *this ;
    }
    void StrVec::push_back(const std::string &s) {
        chk_n_alloc() ;  //首先检查 StrVec
        alloc.construct(frist_free++,s); //构造元素放入即可
    }
    void StrVec::reserve( size_t new_cap ) {
        if( new_cap > capacity() ) {  //beyond the capacity , Redistribution 
            reallocate(new_cap) ;
        }
    }
    //增大容器或缩小容器,其中的对象也会被构造好
    void StrVec::resize(size_t count, const std::string &value )
    {
        if (count > size() ) {
            if (count > capacity()) reserve(count * 2) ;
            for (size_t i = size(); i != count ; ++i)
                alloc.construct(frist_free++, value);
        }
        else if (count < size( )) {
            while (frist_free != elements + count)
                alloc.destroy(--frist_free) ;
        }
    }
    //拷贝和赋值StrVec 时,需要用到(StrVec)是类值的对象 ,不同对象不同内存
    std::pair<std::string * ,std::string *> StrVec::alloc_n_copy(const std::string *b,const std::string *e){
        auto data = alloc.allocate( e - b ) ;  
        return { data ,uninitialized_copy(b,e,data)  } ;
    }
    
    // for loop Method 
    /*void StrVec::free(){  //销毁元素并释放内存
        if( elements ){    // why judge it ? you should think it 
            for(auto p = frist_free ; p != elements ; )
                alloc.destroy(--p) ; //must is --p  
        }
        alloc.deallocate( elements ,cap - elements ) ;
    }*/
    
    // for_each  and lambda Method 
    void StrVec::free(){  
        if( elements ){ 
            for_each( elements , frist_free ,  [this]( std::string &p){
                alloc.destroy( &p ) ; // need you to look out !!!!!! 
            } );  
            alloc.deallocate( elements ,cap - elements ) ;
        }
    }
    
    void StrVec::reallocate(size_t temp  ) { 
        size_t newcapacity ;
        if(temp ==  1  )
            newcapacity = size() ? 2*size() : 1 ; 
        else 
            newcapacity = temp ; 
        auto newdata = alloc.allocate( newcapacity );
        auto dest = newdata ;
        auto elem = elements ;
        for(size_t i= 0 ;i != size() ;i++){
            alloc.construct(dest++,std::move(*elem++)) ;
        }
        free();
        elements = newdata ;
        frist_free = dest ;
        cap = elements + newcapacity ;
    }
    StrVec::~StrVec(){
        free() ;
    }
    int main(void){
        StrVec temp ;
        temp.push_back("1") ;
        temp.push_back("2") ;   
        temp.push_back("3") ;
        temp.push_back("4") ;
        temp.push_back("5") ; //now the size() = 5  ,capacity() == 8  
    
        for(auto i : temp )
            std::cout << i << " ";
        std::cout << std::endl ;
    
        std::cout  << temp.size() << std::endl ;
        std::cout  << temp.capacity() << std::endl << std::endl ;
    
        temp.reserve(52) ;  //the capacity shouble is 52 
         for(auto i : temp )
            std::cout << i << " ";
        std::cout << std::endl ;
    
        std::cout  << temp.size() << std::endl ; //  5 
        std::cout  << temp.capacity() << std::endl << std::endl ;
    
        temp.resize(2) ;  //size() = 2 ,capacity = 52 
         for(auto i : temp )
            std::cout << i << " ";
        std::cout << std::endl ;
    
        std::cout  << temp.size() << std::endl ;
        std::cout  << temp.capacity() << std::endl << std::endl ;
    
        temp.resize(150) ;   //capacity = 300 ,size() = 150 
         for(auto i : temp )
            std::cout << i << " ";
        std::cout << std::endl ;
    
        std::cout  << temp.size() << std::endl ;  
        std::cout  << temp.capacity() << std::endl << std::endl ;
    
        StrVec temp2={"6","7","8","9","10"}; //test the std::initializer_list
        for(auto i : temp2 )
            std::cout << i << " ";
        std::cout << std::endl ;
    
        std::cout  << temp2.size() << std::endl ;
        std::cout  << temp2.capacity() << std::endl << std::endl ;
        return 0 ;
    }

    实现效果:

    这里写图片描述

    几个知识点的总结:

    1.pair 模板 and uninitialized_copy和copy 的区别

    std::pair<std::string * ,std::string *> StrVec::alloc_n_copy(const std::string *b,const std::string *e){
    auto data = alloc.allocate( e - b ) ;  
    return { data ,uninitialized_copy(b,e,data)  } ;
    }
    
    copy 是依次调用重载的运算符= 
    uninitialized_copy是依次调用拷贝构造函数
    如果目标区间是未初始化的,应该用uninitialized_copy, 否则用copy
    

    2.lambda 表达式 and for_each

    // for_each  and lambda Method 
    void StrVec::free(){  
        if( elements ){ 
            for_each( elements , frist_free ,  [this]( std::string &p){
                alloc.destroy( &p ) ; // need you to look out !!!!!! 
            } );  
            alloc.deallocate( elements ,cap - elements ) ;
        }
    }

    这样写要比写成循环要好一点,它不需要担心顺序和递减,所以更直接和方便。而且比个也要高一点。使用这种方法唯一要做的就是添加“&”来构建指向字符串指针的指针。

    3.移动构造函数和 std::move

    for(size_t i= 0 ;i != size() ;i++){
            alloc.construct(dest++,std::move(*elem++)) ;
        }

    std::move函数可以以非常简单的方式将左值引用转换为右值引用。

    通过std::move,可以避免不必要的拷贝操作。

    std::move是为性能而生。

    std::move是将对象的状态或者所有权从一个对象转移到另一个对象,只是转移,没有内存的搬迁或者内存拷贝。

    4. reserve and resize

    1、resize(n)

    调整容器的长度大小,使其能容纳n个元素。

    如果n小于容器的当前的size,则删除多出来的元素。

    否则,添加采用值初始化的元素。

    2、 resize(n,t)

    多一个参数t,将所有新添加的元素初始化为t。

    而reserver()的用法只有一种

    reserve(n)

    预分配n个元素的存储空间。

    了解这两个函数的区别,首先要搞清楚容器的capacity(容量)与size(长度)的区别。

    size指容器当前拥有的元素个数;

    而capacity则指容器在必须分配新存储空间之前可以存储的元素总数。也可以说是预分配存储空间的大小。

    resize()函数和容器的size息息相关。调用resize(n)后,容器的size即为n。

    至于是否影响capacity,取决于调整后的容器的size是否大于capacity。

    reserve()函数和容器的capacity息息相关。

    调用reserve(n)后,若容器的capacity小于 n,则重新分配内存空间,从而使得capacity等于n。

    如果capacity>=n呢?capacity无变化。

    从两个函数的用途可以发现,容器调用resize()函数后,所有的空间都已经初始化了,所以可以直接访问。

    而reserve()函数预分配出的空间没有被初始化,所以不可访问。

    5. std::initializer_list

    c++initializer_list详解

  • 相关阅读:
    框架面试题
    Mybatis的配置文件
    better-mybatis-generator逆向工程
    mysql-5.7.26-linux-glibc2.12-x86_64.tar.gz的安装与配置
    apache-tomcat-8.5.40.tar.gz的安装与配置
    Linux系统的CentOS 7安装,Linux系统的登陆, VMware 12(32/64位)下载地址,VMware 15(32/64位)下载地址,安装VMware 12
    jdk-8u211-linux-x64.tar.gz的安装
    Javaweb的学习笔记(部分总结)
    蜂窝背景页面特效
    Linux操作系统ip的设置和vm快照
  • 原文地址:https://www.cnblogs.com/Tattoo-Welkin/p/10335295.html
Copyright © 2020-2023  润新知