zoukankan      html  css  js  c++  java
  • 内存管理之智能指针shared_ptr

    智能指针(smart pointer)


    智能指针的行为类似常规指针,重要的区别在于智能指针负责自动释放所指向的对象,头文件memory
    shared_ptr : 允许多个智能指针指向同一个对象
    unique_ptr : 一个指针“独占”所指向的对象
    weak_ptr : 弱引用,指向shared_ptr所管理的对象
     
     
    shared_ptr:

    1.创建一个shared_ptr,必须提供指针指向的类型,命名格式:shared_ptr<类型> 指针名;
    例如:shared_ptr<string> sptr 或 shared_ptr<vector<int>> vctptr,上述形式的初始化,返回的智能指针中保存一个空指针
     
    2.与普通指针相似,解引用(*)智能指针返回它指向的对象
     
    3.shared_ptr支持的操作,参看c++ primer 5 Edition P401
     
    4.make_shared函数:作为智能指针的初始化方式之一,安全的分配和使用动态内存。功能:在动态内存中,分配一个对象并初始化,返回此对象的shared_ptr,
    格式:shared_ptr<类型> 指针名 = make_shared<类型>();例如:
    shared_ptr<int> iptr = make_ptr<int>(); // 使用int的默认构造函数,初始化shared_ptr对象的内容
    shared_ptr<int> iptr = make_ptr<int>(36); // 使用int的重载构造函数,初始化shared_ptr对象的内容为36

    5.shared_ptr的拷贝和赋值

    当拷贝和赋值操作时,每个shared_ptr都会记录有多少个其他的shared_ptr指向相同的对象,即:每个shared_ptr都有一个关联的计数器,引用计数;无论何时拷贝(赋值)一个shared_ptr,计数器都会递增。
     
    递增的情况有三种(这里类似复制构造函数,存在的情形):
    a.用一个shared_ptr初始化另外一个shared_ptr
    b.作为函数参数传参(拷贝实参对象)
    c.作为函数返回值(返回出来还是要赋值)
     
    指向同一对象的所有shared_ptr指针的计数都相同,同时更新(+1或-1),一旦计数器变为0,则会自动释放shared_ptr所管理的对象
     
    智能指针初始化方式:
    shared_ptr<int> iptr = make_shared<int>(5);
    cout << iptr.use_count() << endl;
    shared_ptr<int> data = make_shared<int>(1); // 初始化方式1:make_shared
    // shared_ptr<int> data(iptr); 初始化方式2:直接初始化
    iptr = data; // 初始化方式3:赋值:智能指针之间相互赋值
    cout << *iptr << endl;
    cout << data.use_count() << endl;
    智能指针只能用只能指针来初始化,或者相互赋值;不能用内置类型指针来赋值,可以用内置类型指针直接初始化
    6.shared_ptr自动销毁管理对象,也会自动释放相关联的动态内存
     
    指向一个对象的最后一个shared_ptr销毁时,shared_ptr类会自动销毁此对象,该类中有析构函数,shared_ptr的析构函数会自动递减它所指向的对象的引用计数,当变为0时,shared_ptr的析构函数就会销毁对象,并释放占用的内存。
    对于一块内存,shared_ptr类保证只要有任何shared_ptr对象引用它,就不会被释放掉
     
    例子1:
    // func返回一个shared_ptr,指向一个动态分配的对象
    shared_ptr<foo> func(T arg) {
        return make_shared<foo>(arg);
    }
    foo类,使用T类型参数arg,通过构造函数初始化一块内存,nake_shared函数将该内存地址返回给智能指针shared_ptr,
    并作为函数func的返回值,返回一个shared_ptr,可以确保在函数体内申请的动态内存会在恰当的时刻被释放
    例子2:
    void func2(T arg) {
        shared_ptr<foo> p = make_shared<foo>(arg);
       // 使用p, 当p离开作用域,它指向的内存会被自动释放
    }
    例子3:
    shared_ptr<foo> func3(T arg) {
        shared_ptr<foo> p = make_shared<foo>(arg);
        return p;  
        // 使用p,当返回p时,引用计数进行了递增操作,当p离开作用域,它指向的内存会被自动释放
    }
    return语句向此函数的调用者返回一个P的拷贝。拷贝一个shared_ptr会增加所管理的对象的引用计数值;当p销毁时,该内存还有其他使用者,内存就不会被释放

    如果忘记了销毁程序不再需要的shared_ptr,程序仍然会正常运行,但是会浪费内存。shared_ptr在无用之后仍然保留的一种可能情况:shared_ptr放在容器中,然后重排了容器,从而不再需要某些元素,在这种情况下,应该erase删除不需要的shared_ptr指针。

     
    7.shared_ptr一些初始化操作:直接内存管理(参考内存管理---直接内存管理)
    前面5提到过shared_ptr的初始化,总结一下:
    1.不进行初始化,会自动初始化为一个空指针nullptr
    shared<类型> 指针名;例如:shared_ptr<int> pi;  
    2.使用内置类型指针直接初始化
    shared_ptr<类型> 指针名(内置类型指针p); 这里的p --> 类型* p = new 类型()
    shared_ptr<类型> 指针名(new<类型>())// shared_ptr与new结合使用
    3.shared_ptr<类型> 指针名(智能指针ptr); // 使用智能指针直接初始化
    4.shared_ptr<类型> 指针名 = 智能指针ptr; //智能指针赋值初始化
    5.shared_ptr<类型> 指针名 = make_shared<类型>(); // make_shared函数初始化
    不能将一个内置指针隐式的转换成一个智能指针,必须使用直接初始化的形式
    一个用来初始化智能指针的普通指针必须指向动态内存,因为智能指针默认使用delete释放它所关联的对象
     
    8.定义改变shared_ptr的其他方法  参看c++ primer 5 Edition P412-413
     
    9.不要混合使用普通指针和智能指针
    当一个shared_ptr绑定到一个普通指针时,就将内存的管理责任交给了shared_ptr
     
    10.不要使用智能指针get()方法初始化另一个智能指针或者智能指针赋值
    get()方法可以获取该智能指针的对应的内置指针,该内置指针指向智能指针管理的对象
    使用get()返回的指针代码不能delete此指针,因为该返回的内置指针指向智能指针管理的对象,该对象的释放由智能指针来管理
     
    11.智能指针和异常:智能指针可以保证当程序发生异常时,仍旧能正确的释放资源
  • 相关阅读:
    BZOJ 4260 Codechef REBXOR
    [SHOI2008]小约翰的游戏John
    [POI2016]Nim z utrudnieniem
    [CQOI2013]棋盘游戏
    [SDOI2016]硬币游戏
    [BZOJ3083]遥远的国度
    [Luogu3727]曼哈顿计划E
    [HihoCoder1413]Rikka with String
    [CF666E]Forensic Examination
    [BZOJ4004][JLOI2015]装备购买
  • 原文地址:https://www.cnblogs.com/zhang716921/p/10626709.html
Copyright © 2011-2022 走看看