C++智能指针

        简单介绍c++11的四种智能指针的用法。使用智能指针需要包含头文件#include<memory>。c++11提出了四种智能指针auto_ptr,unique_ptr,shared_ptr和weak_ptr。

1.auto_ptr:

        auto_ptr是使用raii机制设计的智能指针,它在构造时申请动态内存,析构时释放动态内存。

使用方法如下:

#include<memory>
#include<iostream>

int main() {
	std::auto_ptr<int32_t> p(new int32_t(10));	//创建时指定动态对象
	std::auto_ptr<int32_t> q;	//创建空智能指针
	q.reset(new int32_t(9));	//绑定对象
	std::cout << *p;
	std::cout << *q.get();	//q.get()得到普通指针int32_t*
	
	return 0;
}

        但是由于浅拷贝的原因,当我们拷贝智能指针后,程序出现了两个指向相同对象的智能指针,此时如果程序退出那么一定会有一个智能指针在释放内存时内存已释放完毕,产生错误。

        出于上面原因可以说几乎所有程序都不要使用auto_ptr。

2.unique_ptr:

        unique_ptr通过禁用拷贝构造函数和=复制语句来避免auto_ptr的情况,不过可以使用=来进行移动构造。用法如下:

#include<memory>
#include<iostream>

int main() {
	std::unique_ptr<int32_t> p(new int32_t(10));	//创建时指定动态对象
	std::unique_ptr<int32_t> q;	//创建空智能指针
	q.reset(new int32_t(9));	//绑定对象
	std::cout << *p;
	std::cout << *q.get();	//q.get()得到普通指针int32_t*

	std::unique_ptr<int32_t> f;
	f = std::move(q);	//移动构造函数赋值
	std::cout << *f;
	//std::cout << *q; 此时该语句是错误的,因为q的内容已经转移给了f,q是空指针

	return 0;
}

        因此在使用auto_ptr的场景我们使用unique_ptr即可。

3.shared_ptr:

        假如我们必须存在多个指向同一内存的智能指针,那么unique_ptr就不太合适了。此时我们可以使用shared_ptr,它通过引用计数的方式来记录同一块内存被指向的智能指针数,析构时会判断计数是否为1,如果是则释放,反之则减一且不释放。用法如下:

#include<memory>
#include<iostream>

int main() {
	std::shared_ptr<int32_t> p(new int32_t(10));	//创建时指定动态对象
	std::shared_ptr<int32_t> q = p;    //赋值
	std::shared_ptr<int32_t> f(new int32_t(9));
	f.swap(p);    //交换p和f的指向,但是等于p的q不会被交换
	std::cout << *p << ' ' << *q << ' ' << *f;    //输出9 10 10

	return 0;
}

        引用计数的实现是采用一个int*指针实现的,当拷贝时新指针的int*指针指向原来的计数块。

        shared_ptr会出现内存泄漏问题,即循环引用,试想如下情况:

std::shared_ptr<node> p(new node());
std::shared_ptr<node> q(new node());
p->ptr = q;
q->ptr = p;

        此时p和q的计数都是2,当析构时,p和q各计数减一,然后此时发现还有计数,因此不调用析构函数释放ptr,此时没有任何方式能拿到ptr,产生内存泄漏。

        使用shared_ptr还需要避免使用同一个原始指针多次初始化shared_ptr,代码如下:

int* p = new int(1);

//下述代码错误,此时p1和p2的引用计数都是1,析构时会产生double free
std::shared_ptr<int> p1(p);
std::shared_ptr<int> p2(p);

//下述代码正确,p1和p2此时的计数都是2
std::shared_ptr<int> p1(p);
std::shared_ptr<int> p2=p1;

        shared_ptr在读的时候是线程安全的,但是在写的时候不是。写的时候线程不安全原因引用陈硕老师的例子(原文地址:为什么多线程读写 shared_ptr 要加锁?_陈硕的博客-CSDN博客):

 

 

4.weak_ptr:

        weak_ptr和shared_ptr共同使用可以解决循环引用问题。weak_ptr赋值时引用计数不加一。它的用法和shared_ptr几乎一样,且可以和shared_ptr互相使用=拷贝。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值