• c++ 11学习笔记--智能指针


    C++ 98的 std::auto_ptr已经被彻底遗弃了,取而代之的是unique_ptr、shared_ptr与weak_ptr。大部分时候我们自己手动申请内存方式内存都是没有问题的,问题是如果程序很大了之后,一个复杂的对象,多次拷贝的代价非常高,很多地方都会使用到,只存在一份拷贝显然是最好的,这个时候对象生命周期的管理就会很复杂,所以c++引入了智能指针。

    任何事物都会有两面性。

    Shared_ptr

    1. 摘录于Effective C++, 3rd Edition, Item 17: 在 standalone statements(独立语句)中将 new 出来的 objects(对象)存入 smart pointers(智能指针)

    比如

    class Widget {
    public:
        Widget() {
            cout << "construct Widget!!!" << endl;
        }
        ;
        ~Widget() {
            cout << "destruct Widget!!!" << endl;
        }
        ;
    };
    
    
    int priority()
    {
        cout << "22222" << endl;
        return 0;
    }
    
    void processWidget(int priority,std::shared_ptr<Widget> pw)
    {
       cout << "111111" << endl;
    
    }
    
    int main()
    {
        processWidget(priority(),std::shared_ptr<Widget>(new Widget));
        
        return 0;
    } 

    processWidget运行的过程应该是

    1.     New Widget

    2.           shared_ptr constructor

    3.         Priority()

    我在llvm上测试的结果也是这个执行顺序

    也许某些编译器上可能执行的顺序是

    1.   New Widget
    2.   Priority() //发生异常
    3.   shared_ptr constructor

    就有可能有内存泄露

    所以最好的办法还是应该把new widget提到外面来写,所以好的编码习惯很重要。

    2.循环引用

    #include <iostream>
    
    using namespace std;
    class A;
    class B;
    typedef std::shared_ptr<A> APtr;
    typedef std::shared_ptr<B> BPtr;
    
    class A {
    public:
        BPtr b;
        ~A () {
             cout << "A released" << endl;
        }
    };
    
    class B {
    public:
        APtr a;
        ~B () {
            cout << "B released" << endl;
        }
    };
    
    int main () {
        APtr a(new A());
        BPtr b(new B());
        
        a->b = b; // 1
        b->a = a; // 2
        
         cout << "over!!" << endl;
        return 0;
    }

    要解决这个问题就需要引入一个弱引用的智能指针了weak_ptr

    class A;
    class B;
    
    typedef std::shared_ptr<A> APtr;
    typedef std::shared_ptr<B> BPtr;
    typedef std::weak_ptr<A> AWeakPtr;
    typedef std::weak_ptr<B> BWeakPtr;
    
    class A {
    public:
        BWeakPtr b; // 注意这里
        ~A () {
            cout << "A released" << endl;
        }
        
    };
    
    class B {
    public:
        AWeakPtr a; // 注意这里
        ~B () {
            cout << "B released" << endl;
        }
        
    };
    
    int main () {
        APtr a(new A());
        BPtr b(new B());
        
        a->b = b;
        b->a = a;
        
        return 0; 
    }

    这两种指针其实和oc里面的 strong, weak非常相识。

     weak_ptr的另外一种用法

    使用情景:当类对象被 shared_ptr 管理时,需要在类自己定义的函数里把当前类对象作为参数传给其他函数时,这时需要传递一个 shared_ptr ,否则就不能保持 shared_ptr 管理这个类对象的语义(因为有一个 raw pointer 指向这个类对象,而 shared_ptr 对类对象的这个引用没有计数,很有可能 shared_ptr 已经把类对象资源释放了,而那个调用函数还在使用类对象——显然,这肯定会产生错误)。《摘录:http://blog.csdn.net/zhongguoren666/article/details/8617436》

    直接看官网的例子吧:

    《http://en.cppreference.com/w/cpp/memory/enable_shared_from_this》

    #include <memory>
    #include <iostream>
    
    struct Good: std::enable_shared_from_this<Good>
    {
        std::shared_ptr<Good> getptr() {
            return shared_from_this();
        }
    };
    
    struct Bad
    {
        std::shared_ptr<Bad> getptr() {
            return std::shared_ptr<Bad>(this);
        }
        ~Bad() { std::cout << "Bad::~Bad() called
    "; }
    };
    
    class CObj: public std::enable_shared_from_this<CObj> {
        friend class CObjMgr;
    protected:
        CObj() {}   // 只有CObjMgr可以创建与删除
        ~CObj(){}
    };
    
    
    int main()
    {
        // Good: the two shared_ptr's share the same object
        std::shared_ptr<Good> gp1(new Good);
        std::shared_ptr<Good> gp2 = gp1->getptr();
        std::cout << "gp2.use_count() = " << gp2.use_count() << '
    ';
        
        // Bad, each shared_ptr thinks it's the only owner of the object
        std::shared_ptr<Bad> bp1(new Bad);
        std::shared_ptr<Bad> bp2 = bp1->getptr();
        std::cout << "bp2.use_count() = " << bp2.use_count() << '
    ';
    } // UB: double-delete of Bad

    1.绝对不能在构造函数中调用shared_from_this()

    因为shared_ptr里面初始化enable_shared_from_this的成员weak_ptr,      这个时候weak_ptr还是空值。

      

    2.为什么内部不能用this指针

    因为我们程序中用shared_ptr来管理指针,如果我们在类的内部传递的过程中用原始指针,这样类内部的引用shared_ptr不会察觉到,因为有可能我们传进去的时候已经被shared_ptr释放掉了。

    unique_ptr

    相对就要单纯许多了,unique_ptr“唯一”拥有其所指对象,只能有一个unique_ptr指向给定对象(通过禁止拷贝语义、只有移动语义来实现)。

    代替普通指针

    void foo()  
    {//不安全的代码  
        X *px = new X;  
        // do something, exception may occurs  
    delete px; // may not go here     
    
    } 
    
    unique_ptr<X> px(new X);  

    在函数中返回对象

    unique_ptr<X> foo()  
    {  
        unique_ptr<X> px(new X);  
        // do something  
        return px; //移动语义  
    }  

    放入容器中

    vector<unique_ptr<string>> vs { new string{“1111”}, new string{“2222”},new string{“3333”}  };  
    
    vector<unique_ptr<string>>v;  
    unique_ptr<string> test(new string("11111"));  
    v.push_back(std::move(test));//使用移动语法

    支持直接持有数组

    std::shared_ptr<int> p(new int[10],
        [](int* p){
            delete[] p;
        });
    //或者使用helper
    std::shared_ptr<int> p(new int[10],std::default_delete<int[]>());
  • 相关阅读:
    json学习系列(1)-使用json所要用到的jar包下载
    Java 时间架构图
    时间纪元与时区介绍
    HTML5 Canvas 绘制库存变化折线
    HTML5 Canvas 笛卡尔坐标系转换尝试
    像孩童一样欣喜的看着自己的成长
    《老炮儿》结尾貌似历史上的一幕
    很多人还在守着金饭碗要饭
    还是用文本编辑器编程让人愉悦
    Node.js 网页爬虫再进阶,cheerio助力
  • 原文地址:https://www.cnblogs.com/budaixi/p/3884710.html
Copyright © 2020-2023  润新知