zoukankan      html  css  js  c++  java
  • C++新特性---智能指针

    智能指针:
        为什么需要智能指针?
            1. malloc出来的空间,没有进行释放,存在内存泄漏的问题。 
            2. 异常安全问题。如果在malloc和free之间如果存在抛异常,那么还是有内存泄漏。这种问题就叫异常安 全。
        RAII:
            是一种利用对象生命周期来控制程序资源(如内存,文件句柄,网络连接,互斥俩个等等)的简单技术
            优点:
                1.不需要显示地释放资源
                2.采用这种方式,对象所需地资源在其生命周期内始终保持有效
     
    // 使用RAII思想设计的SmartPtr类 
    template<class T> 
    class SmartPtr { 
    public:    
        SmartPtr(T* ptr = nullptr)        
            : _ptr(ptr)    
        {}
        
        ~SmartPtr()    {        
            if(_ptr)            
                delete _ptr;    
        }
    private:    
        T* _ptr; 
    };
     
    void MergeSort(int* a, int n) {    
        int* tmp = (int*)malloc(sizeof(int)*n);    
        // 讲tmp指针委托给了sp对象,用时老师的话说给tmp指针找了一个可怕的女朋友!天天管着你,直到你go die^^    
        SmartPtr<int> sp(tmp);    
        // _MergeSort(a, 0, n - 1, tmp);            
        // 这里假设处理了一些其他逻辑    
        vector<int> v(1000000000, 10);    
        // ... 
    }
     
    int main() {    
        try {        
            int a[5] = { 4, 5, 2, 3, 1 };        
            MergeSort(a, 5);    
        }    
        catch(const exception& e)    {        
            cout<<e.what()<<endl;    
        }
        return 0; 
    }
        智能指针原理:
            需要具备指针地行为,可以解引用,也可以通过->去访问所指空间中地内容,因此还需要将*, ->,重载
     
    template<class T> 
    class SmartPtr { 
    public:    
        SmartPtr(T* ptr = nullptr)        
            : _ptr(ptr)    
        {}
        ~SmartPtr()    {        
            if(_ptr)            
                delete _ptr;    
        }        
        T& operator*() {return *_ptr;}    
        T* operator->() {return _ptr;} 
    private
        T* _ptr; 
    };
    struct Date {    
        int _year;    
        int _month;    
        int _day; 
    };
    int main() {    
        SmartPtr<int> sp1(new int);    
        *sp1 = 10    
        cout<<*sp1<<endl;       
     
        SmartPtr<int> sparray(new Date);    
        // 需要注意的是这里应该是sparray.operator->()->_year = 2018;    
        // 本来应该是sparray->->_year这里语法上为了可读性,省略了一个->    
        sparray->_year = 2018;    
        sparray->_month = 1;    
        sparray->_day = 1; 
    }
    总结智能指针的原理:
        1.RAII特性
        2.重载opreator* 和operator->,具有像指针一样的行为
     
    C++11和boost中智能指针的关系
    1. C++98中产生了第一个智能指针auto_ptr
    2. C++boost给出了更实用的scoped_ptr和shared_ptr和weak_ptr
    3. C++11,引入了unique_ptr和share_ptr和weak_ptr.需要注意的是unique_ptr对应boost的scoped_ptr.并且这些智能指针是实现原理是参考boost中的实现的
    auto_ptr {
    
    
    构造->保存指针信息
    析构->释放指针空间
    
    
    auto_ptr<int> ptr(ptr2);
    拷贝构造->(转移管理权的形式,将ptr2赋值给_ptr,置空ptr2)
    
    
    auto_ptr<int> ptr = ptr2;
    赋值运算符重载->(转移管理权,判断是否自己给自己赋值,先释放自己所指向的空间,在用ptr2赋值给_ptr,置空ptr2)
    
    
    }
    unique_ptr {
    //线程安全
    
    //不支持拷贝构造
    C++11:
    unique_ptr(const unique+ptr<T>& ap) = delete;
    unique_ptr<T>& opreator=(const unique_ptr<T>& ap) = delete;
    
    
    C++98:
    //只声明,不实现,声明成私有
    
    
    }
    shared_ptr {
    //会存在引用计数的线程安全问题
    
    //实现了引用计数的方式
    
    ////////////////////////////////////////////////////////////////////////////////////
    //此方法存在一定问题
    private:
        T* _ptr
        statice int _count;
        //使用statice会存在一定问题:
        //使用了statice后每个对象只会公用一块空间,而当需要多块空间来计数的时候就不能实现
        //sp1; sp2(sp1)-> 1和2公用一个空间   sp3; sp4(sp3);->3和4公用一块空间  
        //这样就需要两个引用计数,但是statice后一个类只能存在一个引用计数            
    ////////////////////////////////////////////////////////////////////////////////////
    
    
    
    public:
        shared_ptr(T* ptr)
            :_ptr(ptr)
            ,_pcount(new int(1))
        {}
        
        shared_ptr(const shared_ptr<T>& sp)
            :_ptr(sp._ptr)
            ,_pcount(sp._pcount)
        {
            (*_pcount)++;
        }
    
    
        shared_ptr<T>& operator=(const shared_ptr<T>& sp)
        {
                if(this != &sp)
                {
                    //ptr1; ptr2(ptr1)
                    //ptr3; ptr3 = ptr2;
                    //先判断ptr2的计数是否为0,不为0则不能释放,说明其他指针还在使用
                    if(--(*_pcount) == 0)
                    {
                        delete _pcount;
                        delete _ptr;
                    }
                    _ptr = sp._ptr;
                    _pcount = sp._pcount;
                    (*_pcount)++;
                }
                return *this;
        }
    
    
        ~shared_ptr()
        {
            if(--(*_pcount) == 0)
            {
                delete _ptr;
                delete _pcount;
                _pcount = nullptr;
                _ptr =  nullptr;
            }
        }    
    
    
    private:
        T* _ptr;
        int* _pcount;
        //_pcount 在堆上,会存在线程安全问题
    }
    //shared_ptr 修改确保shared_ptr的线程安全问题
    
    shared_ptr {
    
    public:
        shared_ptr(T* ptr)
            :_ptr(ptr)
            ,_pcount(new int(1))
        {}
        
        shared_ptr(const shared_ptr<T>& sp)
            :_ptr(sp._ptr)
            ,_pcount(sp._pcount)
        {
            (*_pcount)++;
        }
    
        shared_ptr<T>& operator=(const shared_ptr<T>& sp)
        {
                if(this != &sp)
                {
                    //ptr1; ptr2(ptr1)
                    //ptr3; ptr3 = ptr2;
                    //先判断ptr2的计数是否为0,不为0则不能释放,说明其他指针还是只用
                    if(--(*_pcount) == 0)
                    {
                        delete _pcount;
                        delete _ptr;
                    }
                    _ptr = sp._ptr;
                    _pcount = sp._pcount;
                    (*_pcount)++;
                }
                return *this;
        }
    
        ~shared_ptr()
        {
            if(--(*_pcount) == 0)
            {
                delete _ptr;
                delete _pcount;
                _pcount = nullptr;
                _ptr =  nullptr;
            }
        }    
    
    private:
        T* _ptr;
        int* _pcount;
        //_pcount 在堆上,会存在线程安全问题
    }
    
    struct Date{
        int _year;
        int _month;
        int _day;
    };
    shared_ptr 的循环引用问题:
        在链表的情况:
    struct ListNode{
        //ListNode* _next;
        //ListNode* _prev;
        /*
        std::shared_ptr<ListNode> _next;
        std::shared_ptr<ListNode> _prev;
        */
    
        std::weak_ptr<ListNode> _next;
        std::weak_ptr<ListNode> _prev;
    
        ~ListNode()
        {
            cout << "~ListNode()" << endl;
        }
    };
    
    int main()
    {
        std::shared_ptr<ListNode> node1(new ListNode);
        std::shared_ptr<ListNode> node2(new ListNode);   
        cout << node1.use_count() << endl;
        cout << node2.use_count() << endl; 
    
        node1->_next = node2;
        node2->_prev = node1;
    
        cout << node1.use_count() << endl;
        cout << node2.use_count() << endl;
    
        return 0;
    }
            week_ptr——>为了解决shared_ptr产生的循环引用,它并不是RAII思想
                特点:
                    1.不会增加引用计数
                    2.只可以接收shared_ptr赋值给它
                    3.本质并不是一个智能指针
  • 相关阅读:
    多重背包POJ1276不要求恰好装满 poj1014多重背包恰好装满
    哈理工1053完全背包
    求最小公倍数与最大公约数的函数
    Bus Pass ZOJ 2913 BFS 最大中取最小的
    POJ 3624 charm bracelet 01背包 不要求装满
    HavelHakimi定理(判断一个序列是否可图)
    z0j1008Gnome Tetravex
    ZOJ 1136 Multiple BFS 取模 POJ 1465
    01背包 擎天柱 恰好装满 zjut(浙江工业大学OJ) 1355
    zoj 2412 水田灌溉,求连通分支个数
  • 原文地址:https://www.cnblogs.com/cuckoo-/p/11434110.html
Copyright © 2011-2022 走看看