• C++ 智能指针


    A smart pointer is a class object that acts like a pointer but has addiction features. --《C++ Primer》第六版

    一、使用普通指针的问题

    1) 每次调用 remodel,动态分配内存,最后没有释放该资源,将导致memory leak.

    1 void remodel(std::string& str)
    2 {
    3     std::string* ps = new std::string(str);//动态分配内存
    4     ...
    5     str = ps;
    6     return;
    7 }

    2) 即使最后释放资源,但是在中间抛出异常,则delete 语句无法执行,仍导致memory leak.

     1 void remodel(std::string& str)
     2 {
     3     std::string* ps = new std::string(str);//动态分配内存
     4     ...
     5     if(weird_thing())//抛出异常
     6        throw_exception();
     7     str = *ps;
     8     delete ps;//释放动态分配的内存
     9     return;
    10 }

     二、智能指针使用实例

    主要有三种智能指针,auto_ptr/unique_ptr/shared_ptr。定义一个指向类A的智能指针pA:auto_ptr<A> pA(new A)。  

     1 #include <iostream>
     2 #include <string>
     3 #include <memory>
     4 using namespace std;
     5 class Report
     6 {
     7 public:
     8     Report(const string s):str(s){
     9         cout<<"Object created!
    ";
    10     }
    11     ~Report(){
    12         cout<<"Object deleted!
    ";
    13     }
    14     void comment() const{
    15         cout<<str<<"
    ";
    16     }
    17 private:
    18     string str;
    19 };
    20 
    21 int main()
    22 {
    23     {//auto_ptr
    24         auto_ptr<Report> ps (new Report("using auto_ptr"));
    25         ps->comment(); // use -> to invoke a member function
    26     }
    27     cout<<"
    ";
    28     {//shared_ptr
    29         shared_ptr<Report> ps (new Report("using shared_ptr"));
    30         ps->comment();
    31     }
    32     cout<<"
    ";
    33     {//unique_ptr
    34         unique_ptr<Report> ps (new Report("using unique_ptr"));
    35         ps->comment();
    36     }
    37     return 0;
    38 }
    View Code

    结果:当指针生命周期结束时,会自动调用所指向对象的析构函数

     三、使用智能指针的注意

    1) 普通指针和智能指针间需要通过显示转换

    智能指针有显示构造函数,它的参数是指针。普通指针需要显示转换成智能指针:Each of these classes has an explicit constructor taking a pointer as an argument. Thus, there is no automatic type cast from a pointer to a smart pointer object. 

    1 shared_ptr<double> pd;
    2 double *p_reg = new double;
    3 pd = p_reg; // not allowed (implicit conversion)
    4 pd = shared_ptr<double>(p_reg); // allowed (explicit conversion
    5 shared_ptr<double> pshared = p_reg; // not allowed (implicit conversion)
    6 shared_ptr<double> pshared(p_reg); // allowed (explicit conversion)

     2) 智能指针不能非动态分配的对象作为构造函数的参数

    因为它最后会用delete 操作来释放该资源。When pvac expires, the program would apply the delete operator to non-heap memory, which is wrong.

    1 string vacation("I wandered lonely as a cloud.");
    2 shared_ptr<string> pvac(&vacation); // NO!

    四、为什么少使用auto_ptr?

    1) auto_ptr and unique_ptr 策略

    多个智能指针不能同时指向同一个对象。假设 A 指向 C, 当使用 B=A 赋值后,原来的智能指针A就失去了对C的所有权,即不能通过A来访问对象C。

    Institute the concept of ownership, with only one smart pointer allowed to own a particular object. Only if the smart pointer owns the object will its destructor delete the object.Then have assignment transfer ownership.This is the strategy used for auto_ptr and for unique_ptr, although unique_ptr is somewhat more restrictive.

    2) shared_ptr 策略

    引用计数:每次赋值会使计数器递增;指针过期会使计数器递减;当最后一个指针过期(计数器为0)将调用 delete。

    Create an even smarter pointer that keeps track of how many smart pointers refer to a particular object.This is called reference counting.Assignment, for example, would increase the count by one, and the expiration of a pointer would decrease the count by one. Only when the final pointer expires would delete be invoked.

    3)auto_ptr 实例

    多个auto_ptr指向同一个对象,会使原来的指针失效,非法访问

     1 #include <iostream>
     2 #include <string>
     3 #include <memory>
     4 using namespace std;
     5 
     6 int main()
     7 {
     8     //files:一个包含5个string 对象的数组
     9     auto_ptr<string> files[5] = 
    10     {
    11         auto_ptr<string> (new string("Fowl balls")),
    12         auto_ptr<string> (new string("Duck Walks")),
    13         auto_ptr<string> (new string("Chicken Runs")),
    14         auto_ptr<string> (new string("Turkey Errors")),
    15         auto_ptr<string> (new string("Goose Eggs"))
    16     };
    17 
    18     auto_ptr<string> pwin;
    19     pwin = files[2]; //files[2] 失去对象的ownership
    20     cout << "The nominees for best avian baseball film are
    ";
    21     for (int i = 0; i < 5; i++)
    22         cout<<*files[i]<<endl;
    23     cout<<"The winner is "<<*pwin<<"!
    ";
    24     return 0;
    25 }
    View Code

    4) unique_ptr

    当多个unique_ptr指向同一个对象,会产生编译错误

    1 unique_ptr< string> pu1(new string "Hi ho!");
    2 unique_ptr< string> pu2;
    3 pu2 = pu1; //#1 not allowed
    4 unique_ptr<string> pu3;
    5 pu3 = unique_ptr<string>(new string "Yo!"); //#2 allowed

    unique_ptr可以使用new[](delete[])。The auto_ptr template uses delete, not delete [], so it can only be used with new, not with new []. But unique_ptr has a new[], delete[] version: std::unique_ptr< double[]>pda(new double(5)); // will use delete []

     五、如何选择智能指针

    1) shared_ptr

    程序里需要用多个指针指向同一个对象。比如:拥有一个数组指针,且需要标识出一些特别的元素(最大/最小);有两个对象都需要指向第三个类的对象;使用STL容器,容器的对象为指针。

    2) unique_ptr

    程序里不需要多个指针指向同一个对象。比如:把unique_ptr 作为函数的返回值,它指向一块动态分配的内存。

    unique_ptr<int> make_int(int n){
        return unique_ptr<int>(new int(n));
    }
  • 相关阅读:
    java 整合redis缓存 SSM 后台框架 rest接口 shiro druid maven bootstrap html5
    《将博客搬至CSDN》
    前后端分离-定义响应格式化数据
    微服务-Springboot+Redis缓存管理接口代码实现
    java语法
    java后台树形结构展示---懒加载
    后端处理前端传过来的日期的两种方式
    汉字转拼音工具类
    Mybatis的小技巧
    调用高德API,通过输入的地址,如省份、市、区获取经纬度 ,通过输入的经纬度,获取区域详情
  • 原文地址:https://www.cnblogs.com/coolqiyu/p/5590317.html
Copyright © 2020-2023  润新知