C++ 智能指针

一.unique_ptr

定义:

独享它指向的对象。即,同时只有一个unique_ptr指向同一个对象,当unique_ptr销毁时,指向的对象也被销毁

初始化:
//方法一
unique_ptr<AA> p0(new AA("西施"));//分配内存并初始化
//方法二
unique_ptr<AA> p0=make_unique<AA>("西施");//C++14
//方法三
AA *p=new AA("西施");
unique_ptr p0(p);
使用方法:
  1. 重载* 、->操作符,可以像指针使用unique_ptr
  2. 不支持拷贝和赋值
  3. 不要使用同个裸指针初始化多个unique_ptr
  4. get()方法返回裸指针
  5. 不要用unique_ptr管理不是new分配的内存
class AA {
public:
	string m_name;
	AA() {
		cout << m_name << "调用构造函数AA()" << endl;
	}
	AA(const string& name) :m_name(name) {
		cout << "调用构造函数AA(const string& name)" << endl;
	}
	~AA() {
		cout << "调用析构函数" << endl;
	}
};
int main() {
	unique_ptr<AA> pu1(new AA("西施"));

	cout << "裸指针的值为" << pu1 << endl;//输出地址1770
	cout << "pu1输出的结果为" << pu1 << endl;//输出地址1770
	cout << "pu.get()输出结果" << pu1.get() << endl;//输出地址1770
	cout << "pu的地址是:" << &pu1 << endl;//输出地址:F738

	//赋值
	AA* p = new AA("貂蝉");
	unique_ptr pu2 = p;//报错
	
	unique_ptr<AA> pu3 = new AA("西施");//报错
	unique_ptr pu4 = pu1;//报错
}

在这里插入图片描述

使用技巧:
  1. 将unique_ptr赋值给另一个,若源unique_ptr是临时右值,编译器允许;若源unique_ptr存在一段时间,则禁止;(右值:就像是我们拿起一个临时使用的物品,用完之后就会丢弃掉)
unique_ptr<AA> func(){
	unique_ptr<AA> pp (new AA("西施3"));
	return pp;
}
int main(){
	unique_ptr<AA> pu1(new AA("西施1"));
	
	unique_ptr<AA> pu2;
	pu2=unique_ptr<AA> (new AA("西施2"));

	cout<<"调用func()之前"<<endl;
	pu2=func();
	cout<<"调用func()之后"<<endl;
}

在这里插入图片描述

  1. 用nullptr给unique_ptr赋值将释放对象,空的unique_ptr==nullptr;
int main(){
	unique_ptr<AA> pu(new AA('西施');
	cout<<"赋值前"<<endl;
	if(pu!=nullptr) cout<<"pu不是空的"<<endl;
	pu=nullptr;
	cout<<"赋值后"<<endl;
	if(pu==nullptr) cout<<"pu是空的"<<endl;

}

在这里插入图片描述

  1. release()释放对指针的控制权,将unique_ptr置空,返回裸指针;
  2. std::move()可以转移对指针的控制权
void func(const AA* a){
	cout<<a->m_name<<endl;
}
int main(){
	unique_ptr<AA> pu(new AA('西施');
	cout<<"开始调用函数"<<endl;
	func(pu.get());
	//func(pu.release());
	//func(pu);
	//func(move(pu));
	cout<<"调用函数完成"<<endl;
}
  1. reset()释放对象
  2. swap()交换两个unique_ptr控制权
  3. unique_ptr不是绝对安全,若程序中途调用exit()退出,全局unique_ptr自动释放,但是局部unique_ptr无法释放
  4. unique_ptr支持数组具体化,因为重载了操作符[],操作符[]返回的是引用

二.shared_ptr

定义:

shared_ptr共享他指向的对象,多个shared_ptr指向相同的对象,内部采用计数器机制实现

  • 当新的shared_ptr与对象关联,引用计数器+1;
  • 当shared_ptr超出作用域,引用计数器-1
  • 当引用计数器为0时,释放对象
基本用法:

shared_ptr构造函数也是explicit,但是没有删除拷贝构造和赋值函数

初始化:
//方法一
shared_ptr<AA> p0(new AA("西施");
//方法二
shared_ptr<AA> p0=make_shared<AA>("西施");
//方法三
AA * p=new AA("西施");
shared_ptr<AA> p0(p);
//方法四
shared_ptr<AA> p0(new AA("西施");
shared_ptr<AA> p1(p0);//计数器+1
shared_ptr<AA> p1=p0;//计数器+1
使用方法:
  1. 重载 *、->
  2. use_count()方法返回引用计数器的值
  3. unique(),若use_count()为1,返回true
  4. get()返回裸指针
  5. 不要用同个裸指针初始化多个share_ptr;
  6. 不要用shared_ptr管理不是new分配的内存
使用技巧:
  1. 用nullptr给shared_ptr赋值,计数器-1;若计数器为0则释放空间。空的shared_ptr==nullptr
  2. std::move()转移对指针控制权,还可将unique_ptr转移成share_ptr
  3. reset()改变与资源的关联关系
  4. unique_ptr效率更高,占用资源更少

三.weak_ptr

定义:

解决shared_ptr循环引用问题
循环引用(若A没死,则B也不死。若B没死,A也不死)

class AA {
public:
	string m_name;
	AA() {
		cout << m_name << "调用构造函数AA()" << endl;
	}
	AA(const string& name) :m_name(name) {
		cout << "调用构造函数AA(const string& name)" << endl;
	}
	~AA() {
		cout << "调用析构函数" << endl;
	}
	shared_ptr<AA> m_p;
};
class BB{
public:
	string m_name;
	BB() {
		cout << m_name << "调用构造函数AA()" << endl;
	}
	BB(const string& name) :m_name(name) {
		cout << "调用构造函数AA(const string& name)" << endl;
	}
	~BB() {
		cout << "调用析构函数" << endl;
	}
	shared_ptr<BB> m_p;
};
int main(){
	shared_ptr<AA> pa=make_shared<AA>("西施a");
	shared_ptr<BB> pb=make_shared<BB>("西施b");
	cout<<"pa.use_count()="<<pa.use_count()<<endl;
	cout<<"pb.use_count()="<<pb.use_count()<<endl;
	pa->m_p=pb;
	pb->m_p=pa;
	cout<<"pa.use_count()="<<pa.use_count()<<endl;
	cout<<"pb.use_count()="<<pb.use_count()<<endl;
}

在这里插入图片描述

主要成员函数:

lock();//返回shared_ptr
expired();//判断资源是否过期
线程安全问题:

  • 单线程安全,多线程不安全
int main(){
	shared_ptr<AA> pa=make_shared<AA>("西施a");
	{
		shared_ptr<BB> pb=make_shared<BB>("西施b");
		pa->m_p=pb;
		pb->m_p=pa;
		if(pa->m_p.expired()==true)
			cout<<"语句块内部:pa->m_p已过期"<<endl;
		else
			cout<<"语句块内部:pa->m_p.lock()->m_name"<<pa->m_p.lock()->m_name<<endl;
	}
	if(pa->m_p.expired()==true)
			cout<<"语句块外部:pa->m_p已过期"<<endl;
		else
			cout<<"语句块外部:pa->m_p.lock()->m_name"<<pa->m_p.lock()->m_name<<endl;
}

在这里插入图片描述

  • 线程安全
int main(){
	shared_ptr<AA> pa=make_shared<AA>("西施a");
	{
		shared_ptr<BB> pb=make_shared<BB>("西施b");
		pa->m_p=pb;
		pb->m_p=pa;
		shared_ptr<BB> pp=pa->m_p.lock();

		if(pp==nullptr)
			cout<<"语句块内部:pa->m_p已过期"<<endl;
		else
			cout<<"语句块内部:pp->m_name="<<pp->m_name<<endl;
	}
	shared_ptr<BB> pp=pa->m_p.lock();

		if(pp==nullptr)
			cout<<"语句块外部:pa->m_p已过期"<<endl;
		else
			cout<<"语句块外部:pp->m_name"<<pp->m_name<<endl;
}

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值