• C++ 标准库智能指针


      整理一下c++中shared_ptr,weak_ptr,unique_ptr三种指针的使用案例和注意事项,让程序资源更加案例,在标准库中,需要包含<memory>,在boost库中,

      一. 智能指针unique_ptr

        与shared_ptr相似,区别在于unique_ptr是独立拥有对象权,因此只有move语言,无拷贝语义,不做其它详述了。

      二.智能指针share_ptr

      1.基本使用

    class Sam
    {
    public:
        Sam(int v):val(v) {    }
        int32_t val;

        ~Sam()
        {
          std::cout << "~sam()" << std::endl;
        }

    };

    //define
    std::shared_ptr<Sam> p1(new Sam(100));
    std::shared_ptr<Sam> p2 = std::make_shared<Sam>(200);
    p1.reset(new Sam(300));  //new first, delete second
    std::shared_ptr<Sam> p3 = p1;

    //get the base ptr
    Sam* pSam = p1.get();

    //modify
    (*p1).val = 10000;

    //cal is 1
    bool b = p1.unique();

    p1.reset();

      2.高级使用

      (1)使用shared_ptr<list<T>>类型,调用reset的时候list中的所有的Sam对象都会调用析构函数

    std::shared_ptr<std::list<Sam>> lst_ptr( new std::list<Sam>(8, 33));
    std::cout << lst_ptr.get()->size() << std::endl;
    lst_ptr.reset();

      (2)程序不知道自己需要使用多少对象. 且程序需要在多个对象间共享数据,使用vector<shared_ptr<T>>类型:

    std::vector<std::shared_ptr<Sam>> vec_ptr;
    std::shared_ptr<Sam> p1(new Sam(10));
    vec_ptr.push_back(p1);

      (3)定制自己的删除器:在shared_ptr释放时会自动调用 函数删除器而不是默认的析构函数了:

    void Deleter(Sam* obj) {
        std::cout << "Deleter" << std::endl;
    }

    std::shared_ptr<Sam> sp(new Sam(10), Deleter);

      如果将删除器定义成类,则自由性更大,下面的代码执行后会调用析构函数(简单地使用了delete)

    template<typename T>
    class Deleter
    {
    public:
        void operator () (T* x) const
        {
            if (x != NULL)
            {
                std::cout << __LINE__ << std::endl;
                delete x;
                x = NULL;
            }
        }
    };

    std::shared_ptr<Sam> sp(new Sam(10), Deleter<Sam> {})

      3.错误用法

      情形一:一个指针同时放入两个shared_ptr,会在第二个shared_ptr释放时引发异常。

    pSam = new Sam(400);
    std::shared_ptr<Sam> p4(pSam);
    std::shared_ptr<Sam> p5(pSam);

      情形二:数据结构形成环的时候,shared_ptr不能正常工作,需要与weak_ptr协作解决此问题,用例如下:

    class CB;
    class CA;
    
    class CA
    {
    public:
        CA() {}
        ~CA() { std::cout << "~CA()" << std::endl; }
    
        void Register(const std::shared_ptr<CB>& sp)
        {
            m_sp = sp;
        }
    
    private:
        std::shared_ptr<CB> m_sp;
    };
    
    class CB
    {
    public:
        CB() {};
        ~CB() { std::cout << "~CB()" << std::endl; };
    
        void Register(const std::shared_ptr<CA>& sp)
        {
            m_sp = sp;
        }
    
    private:
        std::shared_ptr<CA> m_sp;
    };
    
      std::shared_ptr<CA> spa(new CA);
        std::shared_ptr<CB> spb(new CB);
    
        spb->Register(spa);
        spa->Register(spb);
    
        printf("%d
    ", spb.use_count()); // 2
        printf("%d
    ", spa.use_count()); // 2

      程序结束后,无法释放内存,也没有调用析构函数,智能指针的引用计数都是2,这就是循环引用问题。

      情形三:普通类继承 enable_shared_from_this 的错误情况:

      

    class Y : public std::enable_shared_from_this<Y>
                {
                public:
                    std::shared_ptr<Y> GetSharePtr()
                    {
                        return shared_from_this();
                    }
                };


        Y y;
        std::shared_ptr<Y> spy = y.GetSharePtr(); // 错误, y 根本不是 new 创建的
        Y* y = new Y;
        std::shared_ptr<Y> spy = y->GetSharePtr(); // 错误, 问题依旧存在, 程序直接崩溃

        std::shared_ptr<Y> spy(new Y);
        std::shared_ptr<Y> p = spy->GetSharePtr();
        printf("%d ", p.use_count()); // 2

      前两者错误是因为虽然Y由 enable_shared_from_this派生,但智能指针的数据结构并没有因为new Y的操作赋值 。

      

      三. 智能指针weak_ptr

      构造和析构不会引起引用计数的增加或减少。没有重载 * 和 -> 但可以使用lock获得一个可用的shared_ptr对象,且在所指对象内存已经无效时,返回指针空值nullptr.

      带有的成员函数reset,use_count

    std::shared_ptr<Sam> sam_ptr(new Sam(6));
        std::weak_ptr<Sam> sam_wk = sam_ptr;
    
        std::shared_ptr<Sam> sp = sam_wk.lock();
        if (sp)
        {
            std::cout << (*sp).val << endl;  // 6
        }
        std::cout << sp.use_count() << std::endl;  //2

      

  • 相关阅读:
    Python生成验证码
    Django设置
    OpenStack安装后检查流程总结
    利用src.rpm包修改源码后重新制作rpm包
    Python知识点:distutils常用子模块
    libvirt, libvirt-python, libvirtd 关系浅析
    Python知识点: os.popen
    Python知识点: __import__
    修改initrd.img里ko文件的一个小tips
    关于openstack自动化安装的一点思考
  • 原文地址:https://www.cnblogs.com/hbright/p/9498087.html
Copyright © 2020-2023  润新知