【9】C++四个智能指针

1 智能指针的作用

智能指针的作用是管理一个指针,因为存在以下这种情况:申请的空间在函数结束时忘记释放,造成内存泄漏。所以智能指针的作用原理就是在函数结束时自动释放内存空间,不需要手动释放内存空间。对于编译器来说,智能指针实际上是一个栈对象,并非指针类型,在栈对象生命期即将结束时,智能指针通过析构函数释放有它管理的堆内存。所有智能指针都重载了“operator->”操作符,直接返回对象的引用,用以操作对象。访问智能指针原来的方法则使用“.”操作符。智能指针不等同与普通指针。

2智能指针分类

STL 一共给我们提供了四种智能指针:auto_ptr、unique_ptr、shared_ptr 和 weak_ptr,auto_ptr 是 C++98 提供的解决方案,C+11 已将其摒弃,并提出了 unique_ptr 作为 auto_ptr 替代方案。

3各种智能指针介绍

3.1 unique_ptr

目的:将对象限制为由一个所有者(指针)所有,因为多个所有权会使程序逻辑变得复杂(即只准有一个指针访问对象)
unique_ptr 的构造和移动:
在这里插入图片描述

unique_ptr的基本操作有:

// Automaticptr.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include "pch.h"
#include <iostream>
#include <memory>//智能指针头文件

using namespace std;

struct Task {
	int mId;
	Task(int id) :mId(id) {
		std::cout << "Task::Constructor" << std::endl;
	}
	~Task() {
		std::cout << "Task::Destructor" << std::endl;
	}
};

int main()
{
	// 通过原始指针创建 unique_ptr 实例
	std::unique_ptr<Task> taskPtr(new Task(23));
	//通过 unique_ptr 访问其成员
	int id = taskPtr->mId;
	cout << id <<endl;
	
	//普通指针
	char str[] = "hjdjdt";
	char *ptr =str;
	cout << ptr << endl;
	//[1]unique_ptr
	//目的:将对象限制为由一个所有者所有,即一个指针指向一个对象,不容许多个指针指向一个对象
	//构造智能指针
	auto ptrA = make_unique<string>("guih"); //C++ 14 引入的新函数
	cout <<"智能指针 ptrA:" <<ptrA << endl;
	//cout << "智能指针 ptrA:" << ptrA.get << endl;
	//变更智能指针
	auto ptrB = move(ptrA);
	cout << "智能指针 ptrA:" << ptrA << endl;//ptrA被清空
	cout << "智能指针 ptrB:" << ptrB << endl;//ptrA被赋值给ptrB
	
	//创建空的智能指针
	unique_ptr<int> ptrC;
	//绑定动态对象,创建时没有赋值,需要重新绑定
	ptrC.reset(new int(3));
	
	//创建时指定动态对象
	unique_ptr<int> ptrD(new int(4));

	// 所有权的变化
	int *p_i = ptrD.release();	//释放所有权  
	unique_ptr<string> u_s(new string("abc"));

	//所有权转移(通过移动语义),u_s所有权转移后,变成“空指针” 
	unique_ptr<string> u_s2 = move(u_s); 

	//所有权转移 先释放在设置为空指针
	u_s2.reset(u_s.release());	

	//显式销毁所指对象,同时智能指针变为空指针。与u_s2.reset()等价
	u_s2 = nullptr;
	system("pause");
	return 0;
}

3.2 auto_ptr

auto_ptr 在 C++98 中引入,定义在头文件。其功能和用法类似于 unique_ptr,由 new expression 获得对象,在 auto_ptr 对象销毁时,他所管理的对象也会自动被 delete 掉。auto_ptr 从 C++98 使用至今,从 C++11 开始,引入unique_ptr 来替代 auto_ptr 。
替换的原因:
(1)安全考虑
避免因潜在的内存问题导致程序崩溃 。使用 unique_ptr 时编译出错,与 auto_ptr 一样,unique_ptr 也采用所有权模型,但在使用 unique_ptr 时,程序不会等到运行阶段崩溃
(2)unique_ptr 安全而且灵活
unique_ptr 是个临时右值,编译器允许拷贝语义,原始指针赋值给新的指针时,原始指针会自动被清除。
(3)扩展 auto_ptr 不能完成的功能
(a)unique_ptr 可放在容器中,弥补了 auto_ptr 不能作为容器元素的缺点。
(b)管理动态数组,因为 unique_ptr 有 unique_ptr<X[]> 重载版本,销毁动态对象时调用 delete[]。
(c)自定义资源删除操作(Deleter)。unique_ptr 默认的资源删除操作是 delete/delete[],若需要,可以进行自定义

3.3 shared_ptr

shared_ptr 是一个标准的共享所有权的智能指针,允许多个指针指向同一个对象。原理:shared_ptr维护了一个指向control block的指针对象,来记录引用个数。
shared_ptr 是为了解决 auto_ptr 在对象所有权上的局限性(auto_ptr 是独占的),在使用引用计数的机制上提供了可以共享所有权的智能指针,当然这需要额外的开销:
(1)shared_ptr 对象除了包括一个所拥有对象的指针外,还必须包括一个引用计数代理对象的指针;
(2)时间上的开销主要在初始化和拷贝操作上, * 和 -> 操作符重载的开销跟 auto_ptr 是一样;
(3)开销并不是我们不使用 shared_ptr 的理由,,永远不要进行不成熟的优化,直到性能分析器告诉你这一点。

3.4 weak_ptr

weak_ptr用于避免shared_ptr相互指向产生的环形结构,造成的内存泄漏。weak_ptr count是弱引用个数;弱引用个数不影响shared count和对象本身,shared count为0时则直接销毁。
weak_ptr 被设计为与 shared_ptr 共同工作,可以从一个 shared_ptr 或者另一个 weak_ptr 对象构造而来。weak_ptr 是为了配合 shared_ptr 而引入的一种智能指针,它更像是 shared_ptr 的一个助手而不是智能指针,因为它不具有普通指针的行为,没有重载 operator* 和 operator-> ,因此取名为 weak,表明其是功能较弱的智能指针。它的最大作用在于协助 shared_ptr 工作,可获得资源的观测权,像旁观者那样观测资源的使用情况。观察者意味着 weak_ptr 只对 shared_ptr 进行引用,而不改变其引用计数,当被观察的 shared_ptr 失效后,相应的 weak_ptr 也相应失效。

4 智能指针选择原则

(1)如果程序要使用多个指向同一个对象的指针,应选择shared_ptr。
(2)如果程序不需要多个指向同一个对象的指针,则可使用unique_ptr。

5 参考文献

C++ 智能指针详解
C++ STL 四种智能指针:https://blog.csdn.net/k346k346/article/details/81478223#comments
C++11的智能指针(常见面试问题):https://blog.csdn.net/xy_cpp/article/details/81750575?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章