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.本质并不是一个智能指针
  • 相关阅读:
    报错处理——TypeError: Dog() takes no arguments
    python笔记——爬虫练习
    python笔记——爬虫原理
    Numpy入门练习
    python学习资源
    python笔记——函数的参数(位置参数、默认参数、可变参数、关键字参数、命名关键字参数、参数组合)
    Spyder快捷键
    python笔记——常用的内置函数
    python笔记——dict和set
    python笔记——for和while循环、if条件判断、input输入
  • 原文地址:https://www.cnblogs.com/cuckoo-/p/11434110.html
Copyright © 2011-2022 走看看