C++ 智能指针简介

1、简要介绍
  C++中共有4个智能指针,分别是auto_ptr、shared_ptr、weak_ptr、unique_ptr,其中auto_ptr在C++11中已弃用(由于某些原因可能导致程序崩溃)。智能指针是存储动态分配对象指针的类(相当于封装),用于生命周期的控制,当指针离开其作用域时,自动销毁动态分配的空间,防止内存泄漏。

2、auto_ptr(自动指针)
2.1 相关说明
 (1)C++11中不推荐,unique_ptr对其进行了改进。本身是一个类模板(封装 / 托管),为指针提供了一个有限的垃圾收集工具,允许指针在auto-ptr对象本身被销毁时自动销毁它们指向的元素。
 (2)auto-ptr对象具有获得分配给它们的指针的所有权的特性:对一个元素拥有所有权的auto-ptr对象负责销毁它所指向的元素,并在其自身被销毁时(栈上,离开作用域时)释放分配给它的内存。
 (3)任何两个auto-ptr对象都不应该拥有同一个元素:当两个auto-ptr对象之间发生赋值操作时,所有权被转移,这意味着失去所有权的对象被设置为不再指向元素(它被设置为空指针)。

2.2 代码

#include<iostream>
#include<string>
#include<memory>
using namespace std;

class Person
{
public:
	Person(string newName) : name(newName)
	{
		cout << "Construct person, name: " << name << endl;
	}

	~Person()
	{
		cout << "Destruct person, name: " << name << endl;
	}

	void showPerson()
	{
		cout << "Show person, name: " << name << endl;
	}
	
    string& getName()
	{
		return name;
	}

private:
	string name;
};

int main()
{
	auto_ptr<Person> autoPson(new Person("瓜智"));

	//get():返回智能指针指向的对象地址
	autoPson->showPerson(); //运算符重载
	autoPson.get()->showPerson();
	cout << "Address1: " << &(*autoPson) << endl; //运算符重载
	cout << "Address2: " << &(*(autoPson.get())) << endl;

	cout << endl << "=======================================" << endl << endl;

	//reset(): 释放指向的对象并设置新值
	autoPson.reset(new Person("瓜牛"));

	cout << endl << "=======================================" << endl << endl;

	//release(): 释放指针
	Person *ptrPson = autoPson.release();
	//autoPson->showPerson(); //autoPson.get()->showPerson(); //内部对象指针已指向NULL,程序崩溃
	ptrPson->showPerson();
	delete ptrPson;

	cout << endl << "=======================================" << endl << endl;

	{
		auto_ptr<Person> testPson(new Person("测试")); //栈
	}

	getchar();
	return 0;
}

2.3 运行结果
在这里插入图片描述
3、unique_ptr(唯一指针)
3.1 相关说明
 (1)和auto_ptr在使用上大致相同,unique_ptr不能在两个智能指针之间使用赋值操作,可以使用move函数进行操作。

3.2 代码

int main()
{
	auto_ptr<Person> autoBo(new Person("小波"));
	auto_ptr<Person> autoTao(new Person("小套"));

	autoTao->showPerson();
	autoTao = autoBo;
	autoTao->showPerson();
	//autoBo->showPerson(); //(赋值时)右值对象内部对象指针指向空,导致程序崩溃

	cout << endl << "=======================================" << endl << endl;

	unique_ptr<Person> uniqueSan(new Person("张三"));
	unique_ptr<Person> uniqueSi(new Person("李四"));

	//uniqueSi = uniqueSan; //不可访问赋值运算符(编译报错)
	uniqueSi = std::move(uniqueSan);
	uniqueSi->showPerson();

	cout << endl << "=======================================" << endl << endl;

	if(NULL == uniqueSan) //unique_ptr: 可以直接用智能指针与NULL进行比较
	{
		cout << "uniqueSan is NULL" << endl;
	}

	/*
	if(NULL == autoBo) //auto_ptr: 没有匹配的"=="操作符(编译报错),需要取出内部指针对象(如下)
	{
		cout << "autoBo is NULL" << endl;
	}
	*/
	if(NULL == autoBo.get())
	{
		cout << "autoBo is NULL" << endl;
	}

	getchar();
	return 0;
}

3.3 运行结果
在这里插入图片描述

4、shared_ptr(共享指针)
4.1 相关说明
 (1)共享指针采用引用计数,可与其他shared_ptr对象共享一个对象(指向同一个对象的地址,如下图代码中Person类的对象)。
 (2)共享类型的shared_ptr对象具有获取指针所有权并共享该所有权的能力:一旦它们获得所有权,指针的所有者组将在最后一个所有者释放该所有权时负责对其删除。
 (3)shared_ptr对象只能通过复制其值来共享所有权:如果两个shared_ptr是从同一个(非shared_ptr)指针构造(或生成)的,则它们都将拥有该指针而不共享它,当先释放其中一个对象(删除其托管对象),后释放另一个事,会导致潜在的访问问题。

4.2 代码

int main()
{
	//shared_ptr::use_count: 在此指针上共享所有权的对象数(即:一个Person对象被几个智能指针对象托管/使用)
	//shared_ptr::reset: 删除托管对象,获取新指针

	//创建一个对象(小明),由一个智能指针对象(sharedMing)进行托管(访问操作)
	shared_ptr<Person> sharedMing(new Person("小明"));
	cout << sharedMing.use_count() << endl;//1

	//此时,sharedMing和sharedMing1两个对象都指向小明
	shared_ptr<Person> sharedMing1(sharedMing);
	cout << sharedMing.use_count() << endl;//2
	cout << sharedMing1.use_count() << endl;//2

	//现在,sharedMing2也加入进来(指向小明)
	shared_ptr<Person> sharedMing2(sharedMing1);
	cout << sharedMing.use_count() << endl;//3
	cout << sharedMing1.use_count() << endl;//3
	cout << sharedMing2.use_count() << endl;//3

	//现在呢,sharedMing3也加入进来(指向小明)
	shared_ptr<Person> sharedMing3 = sharedMing;
	cout << sharedMing.use_count() << "  name: " << sharedMing->getName() << endl;//4  小明
	cout << sharedMing1.use_count() << "  name: " << sharedMing1->getName() << endl;//4  小明
	cout << sharedMing2.use_count() << "  name: " << sharedMing2->getName() << endl;//4  小明
	cout << sharedMing3.use_count() << "  name: " << sharedMing3->getName() << endl;//4  小明

	cout << endl << "=======================================" << endl << endl;

	//到这儿,sharedMing不要小明了,转而相中小琴(其他智能指针对象还没放弃小明,少了一个竞争对手,use_count减一)
	sharedMing.reset(new Person("小琴"));
	cout << sharedMing.use_count() << "  name: " << sharedMing->getName() << endl;//1  小琴
	cout << sharedMing1.use_count() << "  name: " << sharedMing1->getName() << endl;//3  小明
	cout << sharedMing2.use_count() << "  name: " << sharedMing2->getName() << endl;//3  小明
	cout << sharedMing3.use_count() << "  name: " << sharedMing3->getName() << endl;//3  小明

	cout << endl << "=======================================" << endl << endl;

	//过了一段时间,sharedMing1和sharedMing2智能指针对象也弃小明而去了
	sharedMing1.reset(new Person("小琴1"));//sharedMing2.use_count: 2
	sharedMing2.reset(new Person("小琴2"));//sharedMing3.use_count: 1

	cout << endl << "=======================================" << endl << endl;

	//终于,sharedMing3也放弃了小明,小明没人要了,就卖了(销毁对象小明,无情)
	sharedMing3.reset(new Person("小琴3"));

	getchar();
	return 0;
}

4.3 运行结果
在这里插入图片描述
5、weak_ptr(弱共享指针)
5.1 相关说明
 (1)weak_ptr是用来解决shared_ptr自身存在的缺陷(两个类之间相互引用shared_ptr对象,导产生对象引用计数不能归0,导致内存泄漏)而设计的。
 (2)weak_ptr也是一个模板类,但是不能直接定义weak_ptr对象,只能配合shared_ptr使用。可以将shared_ptr的对象赋给weak_ptr的对象,同时不会改变引用计数(use_count)。

5.2 代码

#include<iostream>
#include<string>
#include<memory>
using namespace std;

class Teacher;//类前置声明

class Person
{
public:
	shared_ptr<Teacher> sharedTeacher;

	weak_ptr<Teacher> sharedTeacher1;

	string name;

	Person(string newName) : name(newName)
	{
		cout << "Construct person, name: " << name << endl;
	}

	~Person()
	{
		cout << "Destruct person, name: " << name << endl;
	}

	void showPerson()
	{
		cout << "Show person, name: " << name << endl;
	}
};

class Teacher
{
public:
	shared_ptr<Person> sharedPerson;

	shared_ptr<Person> sharedPerson1;

	string course;

	Teacher(string newCourse) : course(newCourse)
	{
		cout << "Construct teacher, course: " << course << endl;
	}

	~Teacher()
	{
		cout << "Destruct teacher, course: " << course << endl;
	}

	void showPerson()
	{
		cout << "Show teacher, course: " << course << endl;
	}
};

int main()
{
	//weak_ptr<Person> weakPerson(new Person("小燕"));//不能直接定义weak_ptr对象,编译不通过

	//问题(方法体结束后,Person和Teacher的两个对象没有被销毁,导致内存泄漏)
	{
		shared_ptr<Person> sharedPerson(new Person("学霸"));
		shared_ptr<Teacher> sharedTeacher(new Teacher("数学"));
		cout << sharedPerson.use_count() << endl;//1
		cout << sharedTeacher.use_count() << endl;//1

		//交叉引用(赋值)
		sharedPerson->sharedTeacher = sharedTeacher;
		sharedTeacher->sharedPerson = sharedPerson;
		cout << sharedPerson.use_count() << endl;//2
		cout << sharedTeacher.use_count() << endl;//2
	}
	//问题(交叉引用后,两个智能指针对象计数都为2,方法体结束后,两个智能指针对象被释放,引用计数各减一,
	//但还存在交叉引用的计数(计数不为0),导致内部托管的对象无法释放,内存泄漏)

	cout << endl << "=======================================" << endl << endl;

	//修改(将两个类中相互引用的智能指针对象,其中一个改为weak_ptr类型,因为weak_ptr不会增加计数)
	{
		shared_ptr<Person> sharedPerson1(new Person("学渣"));
		shared_ptr<Teacher> sharedTeacher1(new Teacher("语文"));
		cout << sharedPerson1.use_count() << endl;//1
		cout << sharedTeacher1.use_count() << endl;//1

		//交叉引用(赋值)
		sharedPerson1->sharedTeacher1 = sharedTeacher1;
		sharedTeacher1->sharedPerson1 = sharedPerson1;
		cout << sharedPerson1.use_count() << endl;//2
		cout << sharedTeacher1.use_count() << endl;//1  Person类中的sharedTeacher1对象未增加计数
	}
	//修改(当Teacher类的"语文"对象引用计数变为0后,释放整个"语文"对象,继而释放"语文"对象中的sharedPerson1)

	getchar();
	return 0;
}

5.3 运行结果
在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值