温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

C++的智能指针使用实例分析

发布时间:2022-03-31 17:08:02 来源:亿速云 阅读:174 作者:iii 栏目:开发技术

今天小编给大家分享一下C++的智能指针使用实例分析的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

    什么是RAII

    RAII(Resource Acquisition Is Initialization)是由C++之父提出的,中文翻译为资源获取即初始化,使用局部对象来管理资源的技术称为资源获取即初始化;这里的资源主要是指操作系统中有限的东西如内存(heap)、网络套接字、互斥量、文件句柄等等,局部对象是指存储在栈的对象,它的生命周期是由操作系统来管理的,无需人工介入

    RAII的原理

    资源的使用一般经历三个步骤:

    • 获取资源(创建对象)

    • 使用资源

    • 销毁资源(析构对象)

    但是资源的销毁往往是程序员经常忘记的一个环节,所以程序界就想如何在程序中让资源自动销毁呢?解决问题的方案就是:RAII,它充分的利用了C++语言局部对象自动销毁的特性来控制资源的生命周期

    裸指针存在的问题

    1.难以区分指向的是单个对象还是一个数组

    2.使用完指针之后无法判断是否应该销毁指针,因为无法判断指针是否”拥有“指向的对象

    3.在已经确定需要销毁指针的情况下,也无法确定是用delete关键字删除,还是有其他特殊的销毁机制,例如通过将指针传入某个特定的销毁函数来摧毁指针

    4.即使已经确定了销毁指针的方法,由于1的原因,仍然无法确定到底是i用delete(销毁单个对象)还是delete[](销毁一个数组)

    5.假设上述的问题都解决了,也很难保证在代码的所有路径中(分支结构,异常导致的挑战),有且仅有一次销毁指针的操作;任何一条路径遗漏都可能导致内存的泄露,而销毁多次则会导致未定义行为

    6.理论上没有方法来分辨一个指针是否处于悬挂状态

    auto_ptr

    class Object
    {
    	int value;
    public:
    	Object(int x = 0) :value(x)
    	{
    		cout << "Create Object:" << this << endl;
    	}
    	~Object()
    	{
    		cout << "Destory Object:" << this << endl;
    	}
    	int& Value()
    	{
    		return value;
    	}
    };
    
    template<class _Ty>
    class my_auto_ptr
    {
    private:
    	bool _Owns;
    	_Ty* _Ptr;
    public:
    	my_auto_ptr(_Ty* p = NULL) :_Owns(p != NULL), _Ptr(p)
    	{}
    	~my_auto_ptr()
    	{
    		if (_Owns)
    		{
    			delete _Ptr;
    		}
    		_Owns = false;
    		_Ptr = NULL;
    	}
    };
    
    void fun()
    {
    	my_auto_ptr<Object> obj(new Object(10));
    }
    
    int main()
    {
    	fun();
    }

    C++的智能指针使用实例分析

    C++的智能指针使用实例分析

    在这里将Object构建完成后,将其指针给到p,当函数结束去调动智能指针的析构函数去释放空间

    若我们需要在fun()函数中,去调用Object类的方法obj->Value();

    class Object
    {
    	int value;
    public:
    	Object(int x = 0) :value(x)
    	{
    		cout << "Create Object:" << this << endl;
    	}
    	~Object()
    	{
    		cout << "Destory Object:" << this << endl;
    	}
    	int& Value()
    	{
    		return value;
    	}
    };
    
    template<class _Ty>
    class my_auto_ptr
    {
    private:
    	bool _Owns;
    	_Ty* _Ptr;
    public:
    	my_auto_ptr(_Ty* p = NULL) :_Owns(p != NULL), _Ptr(p)
    	{}
    	~my_auto_ptr()
    	{
    		if (_Owns)
    		{
    			delete _Ptr;
    		}
    		_Owns = false;
    		_Ptr = NULL;
    	}
    	_Ty* get()const
    	{
    		return _Ptr;
    	}
    	_Ty& operator*()const
    	{
    		return *(get());
    	}
    	_Ty* operator ->()const
    	{
    		return get();
    	}
    };
    
    void fun()
    {
    	my_auto_ptr<Object> obj(new Object(10));
    	cout << obj->Value() << endl;
    	cout << (*obj).Value() << endl;
    }
    
    int main()
    {
    	fun();
    }

    C++的智能指针使用实例分析

    通过运算符重载,(*obj) 后将直接指向堆区(heap)的对象实体

    若我们通过一个my_auto_ptr去创建另一个my_auto_ptr

    class Object
    {
    	int value;
    public:
    	Object(int x = 0) :value(x)
    	{
    		cout << "Create Object:" << this << endl;
    	}
    	~Object()
    	{
    		cout << "Destory Object:" << this << endl;
    	}
    	int& Value()
    	{
    		return value;
    	}
    };
    
    template<class _Ty>
    class my_auto_ptr
    {
    private:
    	bool _Owns;
    	_Ty* _Ptr;
    public:
    	my_auto_ptr(_Ty* p = NULL) :_Owns(p != NULL), _Ptr(p)
    	{}
    	~my_auto_ptr()
    	{
    		if (_Owns)
    		{
    			delete _Ptr;
    		}
    		_Owns = false;
    		_Ptr = NULL;
    	}
    	my_auto_ptr(const my_auto_ptr& obj):_Owns(obj._Owns),_Ptr(obj._ptr)
    	{	
    	}
    	my_auto_ptr& operator=(const my_auto_ptr& _Y)
    	{
    		if(this == &_Y) return *this;
    		if(_Owns)
    		{
    			delete _Ptr;
    		}
    		_Owns = _Y._Owns;
    		_Ptr = _Y._Ptr;
    		return 0;
    	}
    
    	_Ty* get()const
    	{
    		return _Ptr;
    	}
    	_Ty& operator*()const
    	{
    		return *(get());
    	}
    	_Ty* operator ->()const
    	{
    		return get();
    	}
    	void reset(_Ty* p = NULL)
    	{
    		if (_Owns)
    		{
    			delete _Ptr;
    		}
    		_Ptr = p;
    	}
    	_Ty* release()const
    	{
    		_Ty* tmp = NULL;
    		if (_Owns)
    		{
    			((my_auto_ptr*)this)->_Owns = false; //常性进行修改
    			tmp = _Ptr;
    			((my_auto_ptr*)this)->_Ptr = NULL;
    		}
    		return tmp;
    	}
    };
    
    void fun()
    {
    	my_auto_ptr<Object> pobja(new Object(10));
    	my_auto_ptr<Object> pobjb(pobja);
    }
    
    int main()
    {
    	fun();
    }

    如果通过浅拷贝,则两个指针拥有同一个资源,在析构的过程会造成资源的重复释放导致崩溃

    若设置为将其资源进行转移

    my_auto_ptr(const my_auto_ptr& obj):_Owns(obj._Owns),_Ptr(release())
    {
    }
    my_auto_ptr& operator=(const my_auto_ptr& _Y)
    {
    	if(this == &_Y) return *this;
    	if(_Owns)
    	{
    		delete _Ptr;
    	}
    	_Owns = _Y._Owns;
    	_Ptr = _Y.release();
    	return 0;
    }
    void fun(my_auto_ptr<Object> apx)
    {
    	int x = apx->Value();
    	cout<<x<<endl;
    }
    int main()
    {
    	my_auto_ptr<Object> pobja(new Object(10));
    	fun(pobja);
    	int a = pobja->Value();
    	cout<<a<<endl;
    }

    那么上面的过程中,资源会进行转移pobja将不再拥有资源,导致pobja失去资源进而程序崩溃

    这也就是auto_ptr的局限性,也导致该智能指针的几乎没有使用

    unique_ptr

    该智能指针属于唯一性智能指针,将拷贝构造删除,也就不能将其新建另一个对象,同时也不能作为参数传入

    class Object
    {
    	int value;
    public:
    	Object(int x = 0) :value(x)
    	{
    		cout << "Create Object:" << this << endl;
    	}
    	~Object()
    	{
    		cout << "Destory Object:" << this << endl;
    	}
    	int& Value()
    	{
    		return value;
    	}
    };
    
    int main()
    {
    	std::unique_ptr<Object> pobja(new Object(10));
    	//std::unique_ptr<Object> pobjb(pobja); error
    	//不允许
    	std::unique_ptr<Object> pobjb(std::move(pobja));
    }

    通过移动赋值是可以的,通过明确的概念,对其资源进行转移

    同时unique_ptr可以区分其所指向的是一个单独空间,或者是连续的空间

    struct delete_ar_object
    {
    	void operator()(Object* op)
    	{
    		if(op == NULL) return;
    		delete[] op;
    	}
    }
    int main()
    {
    	std::unique_ptr<Object> pobja(new Object(10));
    	std::unique_ptr<Object,delete_ar_object> pobjb(new Object[10]);
    }

    在这里如果是连续空间,会调用删除连续空间的删除器;单独空间则使用默认删除器

    unique_ptr在编写的时候,有多个模板类,分别对应单个对象的方案和一组对象的方案

    并且可以通过智能指针指向fopen打开的文件对象,而文件对象是同fclose去进行关闭的

    struct delete_file
    {
    	void operator()(FILE *fp)
    	{
    		if(fp == NULL) return;
    		fclose(fp);
    	}
    }
    std::unique_ptr<FILE,delete_file> pfile(fopen("zyq.txt","w"));

    这里只需要将默认的删除器,更改为对文件对象的删除器

    以上就是“C++的智能指针使用实例分析”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注亿速云行业资讯频道。

    向AI问一下细节

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    c++
    AI