智能指针 之 unique_ptr shared_ptr weak_ptr



智能指针注意事项

  • 智能指针就是类,类中有一个成员管理着原始指针(他自己的地址和他管理的指针地址是两个东西)
  • 智能指针的目的是解决资源释放问题
  • 智能指针不支持指针运算:+,-,++,–
    但是常规指针支持

独占指针 unique_str

独占指针独享它指向的对象

初始化

方法①
	stu* s1 = new stu("Alice");//类new必须是指针
	unique_ptr <stu> u1(s1);
方法②【常用】
	unique_ptr<stu>u2(new stu("Bob"));
方法③【C++14标准】
	unique_ptr<stu>u3 = make_unique<stu>("Cindy");

使用(相关函数)

  u1->name;
  (*u1).name;//解引用 

赋值nullptr释放对象

赋值NULL后对象被释放,抛出异常

在这里插入图片描述

release 释放控制权

释放对原始指针的控制权,将unique_ptr置为空,返回裸指针
如下图(释放后仍调用会异常)

在这里插入图片描述

move转变原指针控制权

在这里插入图片描述

reset()释放对象

	u1.reset();//释放u1指向的资源对象
	u1.reset(nullptr);//释放u1指向的资源对象
	u1.reset(new stu("Bob"));//释放u1指向的资源对象,并指向新的

在这里插入图片描述

unique_ptr赋值原则

将一个unique_ptr指针赋给另一个时遵循的原则:
右值如果会继续存在则不能赋值(如下不被允许)

unique_ptr <stu> u1(new stu("alice"));
unique_ptr <stu> u2;
u2 = u1 ;//是错误的,因为u1会继续存在

右值时临时变量则可以赋值(如下被允许)

unique_ptr <stu> u2;
u2 = fun();
unique_ptr <stu> fun(){
 unique_ptr <stu>s1(new stu("alice"));
 return s1;
}

多态 demo

#include <iostream>
#include <memory>
using namespace std;
class base {
public:
	virtual void show1() = 0;//纯虚函数
	virtual void show2() {}//虚函数

};
class son1 :public base{
public:
	void show1();
	void show2();
};
void son1::show1() {
	cout << "我是孩子1号重写了base类show1函数" << endl;
}
void son1::show2() {
	cout << "我是孩子1号我重写了base类show2函数" << endl;
}
class son2 :public base {
public:
	void show1();
	void show2();
};
void son2::show1() {
	cout << "我是孩子2号重写了base类show1函数" << endl;
}
void son2::show2() {
	cout << "我是孩子2号我重写了base类show2函数" << endl;
}


int main() {
	int id;
	while (1) {
		cin >> id;
		if (id == 1) {
			unique_ptr <son1> u1(new son1);
			u1->show1();
			u1->show2();
		}
		else {
			unique_ptr <son2> u1(new son2);
			u1->show1();
			u1->show2();
		}
	}
}

在这里插入图片描述

智能指针不是绝对安全的

如果在程序中调用exit()退出,全局unique_ptr可以自动释放,局部的无法释放

智能指针数组

常规类数组指针demo

用完必须手动释放
delete []arr;

#include <iostream>
#include <memory>
using namespace std;
class base {
public:
	virtual void show1() = 0;
	virtual void show2() {}
public:
	string name;
};
class son1 :public base{
public:
	void show1();
	void show2();
};
void son1::show1() {
	cout << "我是孩子1号重写了base类show1函数" << endl;
	cout <<"我叫:" << name << endl;
}
void son1::show2() {
	cout << "我是孩子1号我重写了base类show2函数" << endl;
}
class son2 :public base {
public:
	void show1();
	void show2();
};
void son2::show1() {
	cout << "我是孩子2号重写了base类show1函数" << endl;
	cout << "我叫:" << name << endl;
}
void son2::show2() {
	cout << "我是孩子2号我重写了base类show2函数" << endl;
}

int main() {
	son1* arr = new son1[2];//普通指针数组
	arr[0].name = "Alice";
	arr[1].name = "Bob";
	arr[0].show1();
	arr[0].show2();
	arr[1].show1();
	arr[1].show2();
	delete[]arr;
}

在这里插入图片描述

智能数组指针demo
#include <iostream>
#include <memory>
using namespace std;
class base {
public:
	virtual void show1() = 0;
	virtual void show2() {}
public:
	string name;
};
class son1 :public base{
public:
	void show1();
	void show2();
};
void son1::show1() {
	cout << "我是孩子1号重写了base类show1函数" << endl;
	cout <<"我叫:" << name << endl;
}
void son1::show2() {
	cout << "我是孩子1号我重写了base类show2函数" << endl;
}
class son2 :public base {
public:
	void show1();
	void show2();
};
void son2::show1() {
	cout << "我是孩子2号重写了base类show1函数" << endl;
	cout << "我叫:" << name << endl;
}
void son2::show2() {
	cout << "我是孩子2号我重写了base类show2函数" << endl;
}

int main() {
	unique_ptr <son2[] > arr( new son2[2]);//普通指针数组
	arr[0].name = "Alice";
	arr[1].name = "Bob";
	arr[0].show1();
	arr[0].show2();
	arr[1].show1();
	arr[1].show2();

}

在这里插入图片描述

函数后加delete表示禁用该函数(c++11)

unique_ptr禁用了拷贝构造函数和赋值函数

unique_ptr(const unique_ptr &)=delete;
unique_ptr& operator=(const unique_ptr&)=delete;

如下代码仅用了拷贝构造函数

 stu(string name) = delete;

在这里插入图片描述

unique_ptr注意事项

智能指针是类,可以传地址,如

fun(&pu);
void fun(unique_ptr<stu>*p){
	cout<<(*p)->name;
}

但是首推引用,不能值传递

fun(pu);
void fun(unique_ptr<stu>&p){
	cout<< p->name;
}

共享指针 shared_ptr

  • 多个共享指针可以指向相同的对象(同一个)
    【资源没有被复制,只是被共享】
  • unique_ptr能解决问题不要用shared_ptr,前者更高效,占用资源更少

初始化

方法①
	stu* s1 = new stu("Alice");//类new必须是指针
	shared_ptr <stu> u1(s1);
方法②【常用】
	shared_ptr<stu>u2(new stu("Bob"));
方法③【C++11标准】【推荐】
	shared_ptr<stu>u3 = make_unique<stu>("Cindy");
方法④【注意格式】【无拷贝构造】
	shared_ptr <stu> u1(new stu("Alice"));
	shared_ptr <stu> u2(u1);//可以用括号
	shared_ptr <stu> u3 = u1;//可以用等号
	cout << u3.use_count() << endl;

使用(相关函数)

  u1->name();
  (*u1).name;//解引用 

shared_ptr支持赋值[unique_ptr看情况]

	shared_ptr <stu> u2(u1);//可以用括号
	shared_ptr <stu> u3 = u1;//可以用等号
  • 赋值后左值计数器-1,右值计数器+1
  • 指向资源的指针多一个就+1,少一个就-1
  • 计数器为0会释放资源
	shared_ptr <stu> a1(new stu("Alice"));
	shared_ptr <stu> a2(a1);//可以用括号
	shared_ptr <stu> a3 = a1;//可以用等号
	shared_ptr <stu> b1(new stu("Alice"));
	shared_ptr <stu> b2(b1);//可以用括号
	cout <<"a.count=" << a1.use_count() << endl;
	cout <<"b.count=" << b1.use_count() << endl;
	//a1赋给b1,相当于覆盖了一个b1,b1-1
	b1 = a1;
	cout << "a.count=" << a1.use_count() << endl;
	cout << "b.count=" << b2.use_count() << endl;
	b2 = b1;
	cout << "a.count=" << a1.use_count() << endl;
	cout << "b.count=" << b2.use_count() << endl;

在这里插入图片描述

计数函数 use_count()

在这里插入图片描述

unique() 1为True其他False

不为1为False(为2、3、4都不行)
在这里插入图片描述
必须是1
在这里插入图片描述

其他函数与unique_ptr类似不做演示

智能指针删除器

(缺省删除器)默认情况下,智能指针过期后用delete释放管理的资源,但是程序猿可以自定义删除器,改变释放资源的行为
【形参为原始指针】

unique_ptr删除器[decltype]

缺省|全局函数|lambda|仿函数

	//缺省
	unique_ptr <stu> a11(new stu("Alice"));
	//普通函数
	unique_ptr <stu,decltype(delet)*> a1(new stu("Alice"), delet);
	//lambda
	unique_ptr < stu, decltype(delet_lambda) > a2(new stu("Bob"), delet_lambda);//可以用括号
	//仿函数
	unique_ptr <stu,dele> a3(new stu("Carry"),dele());
	a1.reset();
	a2.reset();
	a3.reset();

在这里插入图片描述

shared_ptr删除器件

缺省|全局函数|lambda|仿函数

#include <iostream>
#include <memory>
using namespace std;
class stu {
public:
	stu(string name) : name(name) {}
	string name;
};
class dele {
public:
	void operator()(stu* a) {
		cout << "仿函数,自定义删除器删除" << endl;
		delete a;
	}

};
void delet(stu* a) {
	cout << "全局函数,自定义删除器删除" << endl;
	delete a;
}
auto delet_lambda = [](stu *a) {
	cout << "lambda函数,自定义删除器删除" << endl;
	delete a;
};
int main() {
	shared_ptr <stu> a11(new stu("Alice"));//缺省
	shared_ptr <stu> a1(new stu("Alice"),delet);
	shared_ptr <stu> a2(new stu("Bob"),delet_lambda);//可以用括号
	shared_ptr <stu> a3(new stu("Carry"),dele());
	a1.reset();
	a2.reset();
	a3.reset();
}

在这里插入图片描述

weak_ptr

为了解决循环引用导致技术永远无法归0,资源部会被释放的问题
weak_ptr是为了配合shared_ptr而引入的,它可以指向一个由shared_ptr管理的资源但不影响生命周期,即绑定之后weak_ptr不影响shared_ptr的引用周期但是他知道对象是否还活着
-【weak_ptr更像shared_ptr的助手,解决它无法处理的循环问题】

shared_ptr出现的问题

【引用计数器失灵,双方都在循环等待对方释放】

#include <iostream>
#include <memory>

using namespace std;
class tec;//要先声明tec,不然stu在声明tec时会未定义
class stu {
public:
	string name;
	stu(string name) : name(name) {
		cout << "我是stu的有参构造函数,我是" << name << endl;
	}
	~stu() {
		cout << "我是stu的析构函数,我是" << name << endl;
	}
	shared_ptr <tec> aa;
};
class tec{
public:
	string name;
	tec(string name) : name(name) {
		cout << "我是stu的有参构造函数,我是" << name << endl;
	}
	~tec() {
		cout << "我是stu的析构函数,我是" << name << endl;
	}
	shared_ptr <stu> aa;
};
int main() {
	
	shared_ptr <stu> student= make_shared <stu> ("Alice");
	shared_ptr <tec> teacher = make_shared <tec>("Bob");
	teacher->aa = student;
	student->aa = teacher;
}

只调用构造不调用析构,很不正常
【引用计数器失灵,双方都在等待对方释放】
在这里插入图片描述
使用weak_ptr之后成功解决
在这里插入图片描述

weak_ptr 成员函数

没有重载->和*,所以不能直接访问资源

operator=()赋值

已经展示过

exptred()判断是否过期

#include <iostream>
#include <memory>


using namespace std;
class tec;//要先声明tec,不然stu在声明tec时会未定义
class stu {
public:
	string name;
	stu(string name) : name(name) {
		cout << "我是stu的有参构造函数,我是" << name << endl;
	}
	~stu() {
		cout << "我是stu的析构函数,我是" << name << endl;
	}
	weak_ptr <tec> aa;
};
class tec{
public:
	string name;
	tec(string name) : name(name) {
		cout << "我是stu的有参构造函数,我是" << name << endl;
	}
	~tec() {
		cout << "我是stu的析构函数,我是" << name << endl;
	}
	weak_ptr <stu> aa;
};
int main() {
	
	shared_ptr <stu> student = make_shared <stu>("Alice"); 
	{
		shared_ptr <tec> teacher = make_shared <tec>("Bob");
		//Bob仅在代码块内声明,代码块外无Bob
		teacher->aa = student;
		student->aa = teacher;
		//weak_ptr提升为shared_ptr
		shared_ptr <tec> flag = student->aa.lock();
		if (student->aa.expired())
			cout << "语句块内部student->aa过期"<<endl;
		else
			cout << "语句块内部student->aa.lock()->name="
			<< student->aa.lock()->name << endl;
	}
	shared_ptr <tec> flag = student->aa.lock();
	//代码块外部Bob失效
	if (student->aa.expired())
		cout << "语句块内部student->aa过期" << endl;
	else
		cout << "语句块内部student->aa.lock()->name="
		<< student->aa.lock()->name << endl;
}

在这里插入图片描述

lock()返回shared_ptr

lock()函数可以提升为shared_ptr,如果对象活着,返回有效的shared_ptr,如果对象死了,提升失败,返回一个空的shared_ptr

//weak_ptr提升为shared_ptr[线程安全]
shared_ptr <tec> flag = student->aa.lock();

reset()置为空|swap()交换|略

总结

  • 智能指针不支持指针运算:+,-,++,–

stu类demo

class stu {
public:
	stu(string name) : name(name) {
		cout << "我是stu的有参构造函数,我是" <<name<< endl;
	}
	~stu() {
		cout << "我是stu的析构函数,我是" << name << endl;
	}
	string name;
};

weak_ptr线程安全用法

		//weak_ptr提升为shared_ptr
		shared_ptr <tec> flag = student->aa.lock();

代码块

  • 如果在代码块”{}”中定义了变量(定义同一个变量),则该变量的生存周期和作用域将被限制在该代码块内。
    如下图
    在这里插入图片描述
  • 若只对变量赋值会改变全局值
    下图只有赋值没有重新定义
    在这里插入图片描述

其他内容后续补充

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值