• 【C++】智能指针简述(四):shared_ptr


      在开始本文内容之前,我们再来总结一下,前文内容:

      1.智能指针采用RAII机制,在构造对象时进行资源的初始化,析构对象时进行资源的清理及汕尾.

      2.auto_ptr防止拷贝后析构释放同一块内存,采用"转移所有权"的方法.(实际开发中auto_ptr并不实用)

      3.scoped_ptr与auto_ptr类似,但是它与auto_ptr最大的区别是:它不能转移所有权,即就是禁止拷贝/赋值!(当然,我们也探讨了C++中禁止拷贝对象的技术,在此不赘述)

      回顾完前文内容后,我们今天来讨论shared_ptr.

      我们虽然有了scoped_ptr,但在实际开发过程中,我们的确要是想对智能指针进行拷贝,那scoped_ptr就鞭长莫及了.

      那么,我们回到原始的问题:对智能指针进行拷贝,会出现什么情况?

      我们在第二篇文章也分析了:如果对智能指针不进行特殊处理,在析构时,会将同一块内存释放多次,程序会崩溃!

      因此,我们要想对智能指针进行拷贝,就必须做一些特殊的处理,使得析构函数只释放一次内存.

      此时,如果探究过深浅拷贝的同学,可能心中已经有了答案:用引用计数!!!(深浅拷贝问题,以后我会讨论,不是本文重点)

      考虑到有些童鞋可能不知道什么是引用计数,那我就在这里解释一下:

      在引用计数中,每一个对象负责维护对象所有引用的计数值。当一个新的引用指向对象时,引用计数器就递增,当去掉一个引用时,引用计数就递减。当引用计数到零时,该对象就将释放占有的资源。——百度百科

      通俗一点的讲:在本例中我们通过count变量来记录当前有多少个对象共同维护着这个指针,每次拷贝/赋值的时候,让count++.

    //拷贝构造(赋值运算符重载类似,用简洁写法调用拷贝构造即可)
    SharedPtr(const SharedPtr &sp)
        :_ptr(sp._ptr)
        ,_count(sp._count){
            if(_count!=NULL){
                ++(*_count);
            }
    }

      当对象析构时,首先我们看count是不是1,如果不是1,说明还有其他对象在维护这个指针,我们让count--.否则的话,就说明,只有当前对象在维护这个指针,此时就可以愉快的把指针delete掉了.

    ~SharedPtr(){
        if(count!=NULL && *count == 1){
            delete _ptr;
            delete _count;
            _ptr = NULL;
            _count = NULL;
        }else{
            --(*count);
        }
    }
    

      通过这样的的形式,就可以保证:在多个shared_ptr对象共同维护一块内存中,对内存只delete一次.

      最终,贴上我简化后shared_ptr的代码.

    /*
    *文件说明:模拟实现shared_ptr
    *作者:高小调
    *日期:2017-03-31
    *集成开发环境:Microsoft Visual Studio 2010 
    */
    #pragma once
    template<typename T>
    class SharedPtr{
    public:
    	//构造函数
    	SharedPtr(T *ptr=NULL)
    		:_ptr(ptr)
    		,_count(NULL){
    			if(ptr!=NULL){
    				_count = new int(1);
    				std::cout<<_ptr<<" Is Created"<<std::endl;
    			}
    	}
    	//拷贝构造
    	SharedPtr(const SharedPtr & sp)
    		:_ptr(sp._ptr)
    		,_count(sp._count){
    			if(sp._count!=NULL){
    				++(*_count);
    			}
    	}
    	//赋值运算符重载
    	SharedPtr& operator=(const SharedPtr &sp){
    		if(_ptr!=sp._ptr){
    			SharedPtr tmp(sp);
    			std::swap(_ptr,tmp._ptr);
    			std::swap(_count,tmp._count);
    		}
    		return *this;
    	}
    	//析构函数
    	~SharedPtr(){
    		if(_count!=NULL && --(*_count)==0){
    			std::cout<<_ptr<<" Is Destory"<<std::endl;
    			delete _ptr;
    			delete _count;
    			_ptr = NULL;
    			_count = NULL;
    		}
    	}
    private:
    	T* _ptr;
    	int *_count;
    };
    
    void TestSharedPtr(){
    	SharedPtr<int> sp1(new int(10));
    	SharedPtr<int> sp2(new int(20));
    	SharedPtr<int> sp3(new int(30));
    	SharedPtr<int> sp4(sp1);
    	sp2 = sp1;
    	sp3 = sp1;
    }
  • 相关阅读:
    JS 反射机制及 Reflect 详解
    React Hooks
    深入理解 React setState
    React 函数组件和类组件的区别
    tsconfig.json 编译器配置大全
    React TS 解决不声明变量类型时的报错问题
    JSX onClick 和 HTML onclick 的区别
    深入理解 ES6 Generator
    JS 算法与数据结构之队列
    深入理解 ES6 Proxy
  • 原文地址:https://www.cnblogs.com/qq329914874/p/6661480.html
Copyright © 2020-2023  润新知