zoukankan      html  css  js  c++  java
  • 智能指针

    https://blog.csdn.net/gettogetto/article/details/66968307

    http://blog.csdn.net/zy19940906/article/details/50470087 

    本次讨论:c++11之前的auto_ptr; c++11新加的unique_ptr, shared_ptr以及weak_ptr。

         头文件:#include <memory>

    一、auto_ptr

    使用模板实现。

    int _tmain(int argc, _TCHAR* argv[])  
    {  
        auto_ptr <Base1> base1(new Base1);//可理解为先声明一个名为base1的Base1类型智能指针,然后再base1里面管理new Base1  
            if (base1.get())//get是智能指针的函数,返回当前当前智能指针对象,即用以判断是否为空  
            {  
               base1->func();  
            }  
            return 0;  
    }  

    1、base1.get():返回当前指针对象;

    2、base1.release():清空当前智能指针对象,并返回类型指针(但并没有释放内存)。

    所以假如我们要正常删除,那么需要这样:

    Base1*base2 = base1.release();  
    delete base2;  
    base2 = NULL;

    3、base1.reset():从图中可看出,是重置智能指针,即把内存删除,且智能指针指向空

    4、auto_ptr还重载了赋值运算符。由图可知意思是把赋值智能指针的内存交给被赋值智能指针,

    auto_ptr <Base1> base2;  
    base2 = base1;//将base1的控制权转交给base2,且base1清空了  
    base2->func();  

    缺点:因此这样就有些问题,控制权可以随便转换,但是只有一个在用,用起来会受到诸多限制

     二、unique_ptr

    C++11引入了许多便捷的功能,其中也包括这个,在用之前我们可以先看下底层:

    可以清楚的看到,unique_ptr中的拷贝构造和赋值操作符delete了,所以也就意味着,他和auto_ptr有区别,控制权唯一,不能随意转换。

    用法都差不多:

    unique_ptr<Base1> base1(new Base1);  
    unique_ptr<Base1> base2;//但是不能用拷贝构造和等号赋值把base1赋值给base2了  

    但是如果想切换控制权的话也不是没有办法,我们可以看到还有个这样的函数:

     

    unique_ptr<Base1> base1(new Base1);  
    unique_ptr<Base1> base2=move(base1);//base1变成empty  
    unique_ptr<Base1> base3;  
    base3 = move(base2);//base2变成empty  

    其它的成员函数就不一一赘述,和auto_ptr大致上是相同的。总结,某种程度来说比auto_ptr更为安全,适用部分特殊情况。

    三、shared_ptr

    如果完全理解了上面两个ptr的底层,那么shared_ptr的也就容易理解多了。但是和前两者有很大区别——

    前两者控制权唯一,切换的时候把前面的清除。而shared_ptr不会,照例看下底层:

    (特殊:赋值:先调用拷贝构造函数,再交换)

    很显然,可以直接赋值和调用拷贝构造函数,且不会清空原本的智能指针。用法就很简单了:

    shared_ptr<Base1> base1(new Base1);  
    shared_ptr<Base1> base2=base1;  
    shared_ptr<Base1> base3;  
    base3 = base2;//三个共享一个  

    有个地方需要注意,当删除一个智能指针时,并不影响其它两个智能指针的继续使用。

    因为该片内存添加了一个引用计数,每构造一次,引用计数+1;每次调用析构函数,引用计数减一。直到最后一个智能指针删除,才会释放内存。

    注意:

    1、在继续查看时,你会发现以下两个函数:

    其实就是和unique_ptr一样可以通过move来切换控制权,这个时候是切换,不是共享了。

    2、接下来继续翻看,还有两个函数:

    (其实auto_ptr也有,只是一样,没必要截图了)

    也就是说,auto_ptr和unique_ptr都可以通过move函数转换成shared_ptr类型,当然,一样是切换控制权的形式,即旧的置空。

    auto_ptr<Base1>   base1(new Base1);  
    shared_ptr<Base1> base2 = move(base1);  

    四、weak_ptr

    weak_ptr更像是shared_ptr的助手:

    1、他不像其余三种,可以通过构造函数直接分配对象内存;他必须通过shared_ptr来共享内存。

    2、没有重载opreator*和->操作符,也就意味着即使分配到对象,他也没法使用该对象

    3、不主动参与引用计数,即,share_ptr释放了,那么weak_ptr所存的对象也释放了。

    4、使用成员函数use_count()可以查看当前引用计数,expired()判断引用计数是否为空。

    5、lock()函数,返回一个shared_ptr智能指针:

    也就是让weak_ptr观测shared_ptr智能指针,并且在需要时候通过lock函数返回一个shared_ptr。

    (https://www.cnblogs.com/diysoul/p/5930372.html)

    weak_ptr 是一种不控制对象生命周期的智能指针, 它指向一个 shared_ptr 管理的对象. 进行该对象的内存管理的是那个强引用的 shared_ptr. weak_ptr只是提供了对管理对象的一个访问手段. 
      weak_ptr 设计的目的是为配合 shared_ptr 而引入的一种智能指针来协助 shared_ptr 工作, 它只可以从一个 shared_ptr 或另一个 weak_ptr 对象构造, 它的构造和析构不会引起引用记数的增加或减少. 
      定义在 memory 文件中(非memory.h), 命名空间为 std.

      weak_ptr 使用:

    std::shared_ptr<int> sp(new int(10));
    std::weak_ptr<int> wp(sp);
    wp = sp;
    printf("%d ", wp.use_count()); // 1
    wp.reset();
    printf("%d ", wp); // 0

    // 检查 weak_ptr 内部对象的合法性.
    if (std::shared_ptr<int> sp = wp.lock())
    {
    }

    成员函数

    weak_ptr 没有重载*和->但可以使用 lock 获得一个可用的 shared_ptr 对象. 注意, weak_ptr 在使用前需要检查合法性.

    expired 用于检测所管理的对象是否已经释放, 如果已经释放, 返回 true; 否则返回 false.
    lock 用于获取所管理的对象的强引用(shared_ptr). 如果 expired 为 true, 返回一个空的 shared_ptr; 否则返回一个 shared_ptr, 其内部对象指向与 weak_ptr 相同.
    use_count 返回与 shared_ptr 共享的对象的引用计数.
    reset 将 weak_ptr 置空.
    weak_ptr 支持拷贝或赋值, 但不会影响对应的 shared_ptr 内部对象的计数.

    使用 weak_ptr 解决 shared_ptr 因循环引有不能释放资源的问题

    使用 shared_ptr 时, shared_ptr 为强引用, 如果存在循环引用, 将导致内存泄露. 而 weak_ptr 为弱引用, 可以避免此问题, 其原理:
      对于弱引用来说, 当引用的对象活着的时候弱引用不一定存在. 仅仅是当它存在的时候的一个引用, 弱引用并不修改该对象的引用计数, 这意味这弱引用它并不对对象的内存进行管理.
      weak_ptr 在功能上类似于普通指针, 然而一个比较大的区别是, 弱引用能检测到所管理的对象是否已经被释放, 从而避免访问非法内存。
    注意: 虽然通过弱引用指针可以有效的解除循环引用, 但这种方式必须在程序员能预见会出现循环引用的情况下才能使用, 也可以是说这个仅仅是一种编译期的解决方案, 如果程序在运行过程中出现了循环引用, 还是会造成内存泄漏.

    class CB;
            class CA;
         
            class CA
            {
            public:
                CA(){}
                ~CA(){PRINT_FUN();}
         
                void Register(const std::shared_ptr<CB>& sp)
                {
                    m_spb = sp;
                }
         
            private:
                std::weak_ptr<CB> m_spb;
            };
         
            class CB
            {
            public:
                CB(){};
                ~CB(){PRINT_FUN();};
         
                void Register(const std::shared_ptr<CA>& sp)
                {
                    m_spa = sp;
                }
         
            private:
                std::shared_ptr<CA> m_spa;
            };
         
            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()); // 1
            printf("%d
    ", spa.use_count()); // 2

    另一个循环依赖的例子,来自<C++标准库(第2版)>

    class Person : public enable_shared_from_this<Person>
    {
    public:
        Person(const string& name)
            : m_name {name}
        {
        }
    
        ~Person()
        {
            cout << "release " << m_name << endl;
        }
    
        string getName() const
        {
            return m_name;
        }
    
        void setFather(shared_ptr<Person> f)
        {
            m_father = f;
            if (f)
            {
                f->m_kids.push_back(shared_from_this());
            }
        }
    
        void setMother(shared_ptr<Person> m)
        {
            m_mother = m;
            if (m)
            {
                m->m_kids.push_back(shared_from_this());
            }
        }
    
        shared_ptr<Person> getKid(size_t idx)
        {
            if (idx < m_kids.size())
            {
                weak_ptr<Person> p = m_kids.at(idx);
                if (!p.expired())
                {
                    return p.lock();
                }
            }
            return nullptr;
        }
    
    private:
        string                        m_name;
        shared_ptr<Person>            m_father;
        shared_ptr<Person>            m_mother;
        //vector<shared_ptr<Person>>    m_kids; // 循环依赖
        vector<weak_ptr<Person>>      m_kids;
    };
    
    
    // 测试代码
        shared_ptr<Person> jack {make_shared<Person>("Jack")};
        shared_ptr<Person> lucy {make_shared<Person>("Lucy")};
        shared_ptr<Person> john {make_shared<Person>("John")};
        john->setFather(jack);
        john->setMother(lucy);
    
        auto p = jack->getKid(0);
        if (p)
        {
            cout << p->getName() << endl;
        }

    VC中的源码实现

    template<class _Ty>
    class weak_ptr
        : public _Ptr_base<_Ty>
    {    // class for pointer to reference counted resource
        typedef typename _Ptr_base<_Ty>::_Elem _Elem;
    
    public:
        weak_ptr()
        {    // construct empty weak_ptr object
        }
    
        template<class _Ty2>
        weak_ptr(const shared_ptr<_Ty2>& _Other,
            typename enable_if<is_convertible<_Ty2 *, _Ty *>::value,
            void *>::type * = 0)
        {    // construct weak_ptr object for resource owned by _Other
            this->_Resetw(_Other);
        }
    
        weak_ptr(const weak_ptr& _Other)
        {    // construct weak_ptr object for resource pointed to by _Other
            this->_Resetw(_Other);
        }
    
        template<class _Ty2>
        weak_ptr(const weak_ptr<_Ty2>& _Other,
            typename enable_if<is_convertible<_Ty2 *, _Ty *>::value,
            void *>::type * = 0)
        {    // construct weak_ptr object for resource pointed to by _Other
            this->_Resetw(_Other);
        }
    
        ~weak_ptr()
        {    // release resource
            this->_Decwref();
        }
    
        weak_ptr& operator=(const weak_ptr& _Right)
        {    // assign from _Right
            this->_Resetw(_Right);
            return (*this);
        }
    
        template<class _Ty2>
        weak_ptr& operator=(const weak_ptr<_Ty2>& _Right)
        {    // assign from _Right
            this->_Resetw(_Right);
            return (*this);
        }
    
        template<class _Ty2>
        weak_ptr& operator=(shared_ptr<_Ty2>& _Right)
        {    // assign from _Right
            this->_Resetw(_Right);
            return (*this);
        }
    
        void reset()
        {    // release resource, convert to null weak_ptr object
            this->_Resetw();
        }
    
        void swap(weak_ptr& _Other)
        {    // swap pointers
            this->_Swap(_Other);
        }
    
        bool expired() const
        {    // return true if resource no longer exists
            return (this->_Expired());
        }
    
        shared_ptr<_Ty> lock() const
        {    // convert to shared_ptr
            return (shared_ptr<_Elem>(*this, false));
        }
    };
  • 相关阅读:
    JBPM 入门阅读
    Jquery ligerui下拉框复选,使下拉框中相应值对勾选中
    spring quartz 1.6配置方法
    断点续传的原理
    转:DWR详细应用介绍
    转:第一个DWR示例
    解决(CXF):SOAPFaultException: Fault occurred while processing
    s2sh保存错误: a different object with the same identifier value was already associated
    解决 java.lang.NoSuchMethodError: org.objectweb.asm.ClassVisitor.visit(IILjava/lang/String;Ljava/lan
    转载:struts2重要标签学习
  • 原文地址:https://www.cnblogs.com/pjl1119/p/9680160.html
Copyright © 2011-2022 走看看