zoukankan      html  css  js  c++  java
  • C++(2)----智能指针与动态内存

    C++ 11提供的智能指针有:shared_ptr、unique_ptr、weak_ptr。在 头文件 memory 中。

    一、new delete 直接管理内存

    1、初始化

    string * ps = new string // 初始换为一个空string 
    int * pi = new int ;//pi 指向一个未初始化的int,*pi 未定义
    
    int * pi = new int(1024); // pi 指向的对象值为1024
    string *ps = new string(10,'9') ; // *ps 为"9999999999"
    
    vector<int> *pv = new vector<int>{0,1,2,3,4,5,6,7,8,9};

    2、释放delete

    int i, *pi1 = &i,  *pi2 = nullptr;
    double *pd = new double(33),  *pd2 =pd;
    
    delete i;  // 错误,, i不是一个动态分配的指针
    delete pi1;  // 未定义错误,  pi1指向一个栈内存指针
    delete pd;   //正确
    delete pd2;  //未定义错误, pd2指向的内存已经被释放
    delete pi2;   //正确:不能释放一个空指针

    delete 之后应该重置指针, 

    int *p(new int(42));
    auto q =p;
    delete p;
    p=q=nullptr

    3、使用new delete 管理内存常出现的问题

        没有delete内存,造成内存泄漏

        使用已经释放掉的对象

        同一块内存释放两次

    二、shared_ptr:

      允许多个指针指向同一个对象。

    定义与初始代码如下:

    // 定义shared_ptr ,默认初始化为空指针
    shared_ptr<string> p1;
    shared_ptr<list<int>> p2;
    
    // make_shared 函数, 头文件 memory
    // 返回一个shared_ptr,  
    // make_shared<T>(args)  使用args初始化对象
    shared_ptr<int> p3 = make_shared<int>(42);
    shared_ptr<string> p4 = make_shared<string>(10,'9') // "9999999999"
    
    shared_ptr<int> p5 = make_shared<int>(); //初始化为 0

    和new 结合初始换

    shared_ptr<int>p2(new int(42));
    
    // 不能混淆普通指针和只能指针
    shared_ptr<int> p1 = new int(1000);  // 错误
    shared_ptr<int> p2(new int(1024));  // 正确
    
    
    // 错误
    shared_ptr<int> clone(int p) {
            return new int(p);      
    }
    // 正确
    shared_ptr<int> clone(int p) {
            return shared_ptr<int>(new int(p));   
    }

    shared_ptr的拷贝和赋值、自动释放

    引用计数; 当对象不再使用时,shared_ptr 会自动释放动态对象;

    auto p = make_shared<int>(42); //p指向的对象只有p一个引用者
    auto q(p);  // 递增一个引用计数
    
    auto r = make_shared<int>(42);   //引用计数为1
    r=q ;    //  给r赋值;  r原来指向的对象引用计数减1; q指向的对象引用计数+1; r原来指向的对象没有引用,自动释放

    当引用计数为0是,内存会被释放,当普通指针  和智能指针混用是可能会出现错误。

    // 一个函数,参数为 shared_ptr<int>
    void process(shared_ptr<int> ptr) {A
          // 使用ptr
    }// ptr离开作用于,销毁释放
    
    /********   正确 ********/
    shared_ptr<int> p(new int(42));   // 引用计数为1
    process(p); // 参数作为值传递,在函数内部引用计数为2,之后为1
    int i = *p; //内有问题, 引用计数值为1;
    
    /*********  错误 ********/
    int *x(new int(1024));   // 这是一个普通的指针
    process(x) ; // 错误,普通指针不能转换为 shared_ptr<int>
    porcess(shared_ptr<int>(x)); //合法,但是危险,函数结束后,会释放内存
    int j =*x ; // 错误,此时内存已经被释放 

    谨慎的使用get() 函数,只有保证内存不被释放的前提现使用。

    不能用get 初始化另一个智能指针,或为另一个智能指针赋值

    // 谨慎使用 get() 函数
    
    shared_ptr<int> p(new int(42));  // 引用计数为1
    int * q = p.get(); // 合法,但是保证内存释放的时机
    
    {// 程序块
      // 不要使用get() 对另一个智能指针初始化,这样对同一块内存,有多个计数
      shared_ptr<int>(q);
    }// q被销毁释放
    int foo = *p; // 此时p所指向的内存已经被释放

    在发生异常时,智能指针也能保证内存被释放

    // 使用 new 分配内存,应当注意由于分支  和 异常造成的内存泄漏
    void f()
    {
          int *ip = new int(42);  // new 动态分配
          // 发生异常
          delete ip;    // 之前发生异常,这里可能造成内存泄漏   
    } 
    
    
    // 使用智能指针, 在发生异常时,内存也会被释放
    void f()
    {
         shared_ptr<int> sp (new int(42)); // 分配一个新对象
         // 发生异常
        
    }//  在函数结束时,shared_ptr 被销毁,同时释放指向的内存

     资源管理《c++primer》:

    三、unique_ptr:

    独占,同一时间只有一个智能指针可以指向这个对象。

    不支持普通的拷贝,和赋值

    unique_ptr<string> p3 (new string ("auto"));    //#4
    unique_ptr<string> p4;                         //#5
    p4 = p3;                                     //   出错
    unique_ptr<string> p4(p3); //出错:不支持拷贝

    unique_ptr<string> p2(p1.release()) // release 将p1置为空
    unique_ptr<string> p3(new string("Trex"));
    // 将所有权从p3转移给p2
    p2.reset(p3.release());

     

    四、weak_ptr

     不控制所指向对象生存期。

    指向由一个shared_ptr管理的对象(由shared_ptr管理生命周期)

    将一个weak_ptr绑定到一个shared_ptr不会改变shared_ptr的引用计数

    // 初始化
    auto p = make_shared<int>(42);
    weak_ptr<int> wp(p);   // 若共享,p的技术不变
    
    // 生命周期由shared_ptr 管理,因此weak_ptr指向的对象可能为空
    // 可使用lock 检查是否为空
    // lock 返回一个指向共享对象的shared_ptr
    if(shared_ptr<int> np = wp.lock())
    {
    .......
    }

     五、智能指针与动态数组

    int *pia = new int[10];   // 10个未初始化的int
    int *pia2 = new int[10]();  //10个值初始化为0的int
    string *psa = new string[10]; //10个空string
    string *psa2 = new string[10](); // 10个空string
    
    int * pia3 = new int[3]{0,1,2};
    
    delete [] pia;


    unique_ptr<int[]> up(new int[10]);
    up.release(); //自动使用delete[] 销毁指针
    // allocator  在头文件memory 中
    //  将内存分配和对象构造分离
    //  分配原始 未构造
    // 是一个模板
    
    allocator<string> alloc;  //可以分配string的allocator 对象
    auto const p = alloc.allocate(n);   //分配n个未初始化的string

    参考:

    https://blog.csdn.net/k346k346/article/details/81478223

    https://www.cnblogs.com/WindSun/p/11444429.html

    《c++ primer》第12章

    https://www.cnblogs.com/KunLunSu/p/7861330.html

  • 相关阅读:
    平衡二叉树
    2020年度总结
    go中string是如何实现的呢
    escape的编码解码
    小程序实现下载图片到手机及文字到手机粘贴板
    小程序分享(单页面,朋友圈)
    sql server单行拆分成多行
    sql server 查询分组后用逗号拼接字符串和拆分
    安装虚拟机
    Lombok插件安装
  • 原文地址:https://www.cnblogs.com/feihu-h/p/12205531.html
Copyright © 2011-2022 走看看