广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++的智能指针你真的了解吗
  • 557
分享到

C++的智能指针你真的了解吗

2024-04-02 19:04:59 557人浏览 八月长安
摘要

目录什么是RaiIRAII的原理裸指针存在的问题auto_ptrunique_ptr总结什么是RAII RAII(Resource Acquisition Is Initializa

什么是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();
}

在这里插入图片描述
在这里插入图片描述

在这里将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();
}

在这里插入图片描述

通过运算符重载,(*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"));

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

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注编程网的更多内容!

--结束END--

本文标题: C++的智能指针你真的了解吗

本文链接: https://www.lsjlt.com/news/144626.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C++的智能指针你真的了解吗
    目录什么是RAIIRAII的原理裸指针存在的问题auto_ptrunique_ptr总结什么是RAII RAII(Resource Acquisition Is Initializa...
    99+
    2022-11-13
  • C++ 智能指针的魅力你都了解吗
    前情提要 我们知道除了静态内存和栈内存外,每个程序还有一个内存池,这部分内存被称为自由空间或者堆。程序用堆来存储动态分配的对象即那些在程序运行时分配的对象,当动态对象不再使用时,我们...
    99+
    2022-11-12
  • 一篇文章带你了解C++智能指针详解
    目录为什么要有智能指针?智能指针的使用及原理RALLshared_ptr的使用注意事项创建多个 shared_ptr 不能拥有同一个对象shared_ptr 的销毁shared_pt...
    99+
    2022-11-12
  • 深入了解C++智能指针的使用
    目录一、C++11智能指针概述二、C++98中的智能指针三、C++11中的智能指针1.unique_ptr2.shared_ptr3.weak_ptr一、C++11智能指针概述 在C...
    99+
    2022-11-13
  • C语言的多级指针你了解吗
    目录前言一、多级指针概念二、多级指针的使用1.二维指针总结前言 自学笔记,没有历史知识铺垫(省略百度部分)C语言了解多级指针的使用 一、多级指针概念 指向指针的指针 即:存放地址的...
    99+
    2022-11-12
  • C/C++编程语言中的指针(pointer)你了解吗
    目录1What2用法示例2.1示例总结1 What 指针,是 C/C++ 编程语言中的一个重要概念。指针通常可以理解为内存地址,而指针变量就是用来存放内存地址的变量。在同一 CPU ...
    99+
    2022-11-13
  • C/C++中智能指针的用法详解
    目录前言一、什么是智能指针二、使用方法1.shared_ptr2.unique_ptr3.weak_ptr前言 本章主要介绍一些C/C++中智能指针的实现原理以及如何使用 一、什么是...
    99+
    2023-01-04
    C++智能指针使用 C++智能指针
  • 深入了解C++中常用的三个智能指针
    目录什么是智能指针C++中的几种智能指针unique_ptrshared_ptrweak_ptr总结什么是智能指针 在C++中,内存的分配和释放都是由开发者手动实现的。这种方式虽然很...
    99+
    2023-05-18
    C++智能指针 内存管理 C++智能指针使用 C++ 智能指针
  • c++智能指针的超详细讲解
    目录1.什么是智能指针2.原始指针的问题3.unique_ptr4.shared_ptr5.shared_ptr使用需要注意的点5.1 不能将一个原始指针初始化多个shared_pt...
    99+
    2022-11-13
  • C++中Boost的智能指针scoped_ptr
    boost::scoped_ptr和std::auto_ptr非常类似,是一个简单的智能指针,它能够保证在离开作用域后对象被自动释放。下列代码演示了该指针的基本应用: #includ...
    99+
    2022-11-13
  • c++智能指针unique_ptr的使用
    目录1.为什么需要unique_ptr2.什么是unique_ptr3.unique_ptr特性4.如何使用unique_ptr4.1简单使用4.2指向数组5.unique_ptr需...
    99+
    2022-11-12
  • C++中Boost的智能指针shared_ptr
    boost::scoped_ptr虽然简单易用,但它不能共享所有权的特性却大大限制了其使用范围,而boost::shared_ptr可以解决这一局限。顾名思义,boost::shar...
    99+
    2022-11-13
  • C++中Boost的智能指针weak_ptr
    循环引用: 引用计数是一种便利的内存管理机制,但它有一个很大的缺点,那就是不能管理循环引用的对象。一个简单的例子如下: #include <string> #includ...
    99+
    2022-11-13
  • C++的运算符你真的了解吗
    目录前言1 算术运算符2 赋值运算符3 比较运算符4 逻辑运算符总结前言 运算符的作用:用于执行代码的运算 主要有: 1 算术运算符 用于处理四则运算 对于前置递增:将递增运算前...
    99+
    2022-11-13
  • C++中的函数你真的理解了吗
    目录1 概述2 函数的定义及调用3 值传递4 函数的常见形式5 函数的声明6 函数的分文件编写作用:让代码结构更加清晰1.2.3.4.总结1 概述 作用:将一段经常使用的代码进行封装...
    99+
    2022-11-13
  • C++中的数组你真的理解了吗
    目录1 概述2 一维数组2.1 一维数组定义方式2.2 一维数组组名2.3 冒泡排序3 二维数组3.1 二维数组定义方式3.2 二维数组数组名3.3二维数组应用举例总结1 概述 所谓...
    99+
    2022-11-13
  • C++的数据类型你真的了解吗
    目录前言1 整型2 sizeof关键字3 实型(浮点型)4 字符型5 转义字符6 字符串型7 布尔类型 bool8 数据的输入总结前言 C++不像python,创建变量的时候必须指定...
    99+
    2022-11-13
  • C++ STL 四种智能指针的用法详解
    目录0.前言1.unique_ptr2.auto_ptr3.shared_ptr 3.1 简介3.2 通过辅助类模拟实现 shared_ptr4.weak_ptr4.1 简...
    99+
    2022-11-12
  • C++重载运算符你真的了解吗
    目录1.重载运算符的必要性2.重载运算符的形式与规则3.重载运算符的运算4.转义运算符总结运算符实际上是一个函数,所以运算符的重载实际上是函数的重载,。编译程序对运算符的重载的选择,...
    99+
    2022-11-13
  • C++11 智能指针的具体使用
    目录智能指针的原理RAII智能指针的原理auto_ptr1.auto_ptr的使用及问题unique_ptrshared_ptrshared_ptr的循环引用智能指针的原理 RAII...
    99+
    2022-11-12
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作