2021-03-19

C++系列之智能指针(smart pointer)

c11开始,standary library 支持两大类型的smart pointer:
1.shared_ptr:共享式指针,多个smart_ptr可以指向同一对象,该对象与其相关资源会在最后一个reference被销毁时释放。同时提供了weak_ptr,bad_weak_ptr,enable_shared_from_this等辅助类;
2.unique_ptr:独占式指针,保证一个对象同一时间只有一个smart_ptr指向该对象。可以转移该对象的拥有权,有效的避免了指针内存泄漏的问题。
shared_ptr的用法:
1.constructor
 (1)	constexpr shared_ptr() noexcept; //默认构造函数
 (2)	constexpr shared_ptr(nullptr_t) : shared_ptr() {} //空指针
 (3)	template <class U> ;explicit shared_ptr (U* p); //显式U*构造
 (4)	template <class U, class D> shared_ptr (U* p, D del);
 		template <class D> shared_ptr (nullptr_t p, D del);  //带有delete的
 (5)	template <class U, class D, class Alloc> shared_ptr (U* p, D del, Alloc alloc);
 		template <class D, class Alloc> shared_ptr (nullptr_t p, D del, Alloc alloc) ; //带有分配器
 (6)	shared_ptr (const shared_ptr& x) noexcept;   
		template <class U> shared_ptr (const shared_ptr<U>& x) noexcept;//拷贝构造函数
 (7)	template <class U> explicit shared_ptr (const weak_ptr<U>& x); //拷贝weak_ptr
 (8)	shared_ptr (shared_ptr&& x) noexcept;
 		template <class U> shared_ptr (shared_ptr<U>&& x) noexcept;   //move构造函数
 (9)	template <class U> shared_ptr (auto_ptr<U>&& x);
  		template <class U, class D> shared_ptr (unique_ptr<U,D>&& x); //其他
(10)	template <class U> shared_ptr (const shared_ptr<U>& x, element_type* p) noexcept;
成元函数:
1.shared_ptr::get();返回普通指针
2.shared_ptr::operator bool:是null->false,other->true
3.shared_ptr::operator *: 返回指针对象
4.shared_ptr::operator->:返回指针对象的成员
5.shared_ptr::operator=:支持拷贝赋值,和move赋值
**6. shared_ptr::owener_before:**
7. shared_ptr::reset: 给sptr重新赋值一个对象的指针
8. shared_ptr::swap:交换两个sptr,不改变各自的引用计数
**9. shared_ptr::unique:判断该对象的sptr是否是唯一的**
**10.shared_ptr::count: 同一对象的sptr的计数**
代码演示
# include<iostream>
# include<memory>
# include<string>
using namespace std;

int main()
{
	//构造函数
	string s1 = "string3";
 	shared_ptr<string> sptr1(new string("string1"));
 	shared_ptr<string> sptr2(sptr1);
 	shared_ptr<string> sptr3(&s1);
 	shared_ptr<string> sptr4;
 	shared_ptr<string> sptr5(unique_ptr<string>(new string("string5")));
	// 成员函数
	sptr3.get();   // return &s1;
	if(sptr1) cout <<"sptr1 is true " <<endl; //cout ture;自动转为bool值
	*sptr1 ;  		//string1;
	sptr1.swap(sptr2);  // swap
	spat1.use_count();   // 指针计数
}	
	
unique_ptr的使用
1.construct
1.constexp unique_ptr() noexcept;    //默认
2.constexp unique_ptr() noexcept : unique_ptr(){};
3.explict unique_ptr( pointer p) noexcept;     
4.unique_ptr(pointer p, typeneme conditon<is_reference<D>::value,D,const D& > del) noexcept;
5.unique_ptr(pointer p, typename remove_reference<D>::type&& del) noexcept;
6.unique_ptr(uniqe_ptr && x) noexcept;  // move
7.template<class U, class E> unique_ptr(unique_ptr<U,E>&& x) noexcept;  //move
8.unique_ptr(const unique_ptr&) = delete;    //废掉了copy
成员函数
1.unique_ptr::get
**2.unique_ptr::get_deleter**
3.unique_ptr::operator bool
4.unique_ptr::operator *
5.unique_ptr::operator ->
6.uniqeu_ptr::operator =
**7.uniqeu_ptr::operator []**
**8.unique_ptr::release**
9.unique_ptr::reset
10.unique_ptr::swap
#include <iostream>
#include <memory>

int main () 
{
  std::default_delete<int> d;
  std::unique_ptr<int> u1;
  std::unique_ptr<int> u2 (nullptr);
  std::unique_ptr<int> u3 (new int);
  std::unique_ptr<int> u4 (new int, d);
  std::unique_ptr<int> u5 (new int, std::default_delete<int>());
  std::unique_ptr<int> u6 (std::move(u5));
  std::unique_ptr<int> u7 (std::move(u6));
  std::unique_ptr<int> u8 (std::auto_ptr<int>(new int));
}
weak_ptr
允许”共享但不拥有“某对象,这个class会建立起一个shared pointer。 一旦最后一个拥有该对象的shared pointer失去了拥有权,任何weak pointer都将会自动变空。因此:在default和copy构造函数外,只提供接收一个shared ptr的构造函数.
成员函数
1. weak_ptr::expired			//判断shared_ptr是否已经不存在
2. weak_ptr::lock					//可以使用该shared_ptr的*,->操作符
4. weak_ptr::operator=		//赋值
5. weak_ptr::owner_before
6. weak_ptr::reset				//置空,null
7. weak_ptr::swap				//交换
8. weak_ptr::use_count		//计数
注意事项

1.避免##循环依赖##出现,从而造成”空荡指针“

class A;
class B
{
	shared_ptr<A> spt1;
}
class A
{
	shared_ptr<B> spt1;
}
int main 
{
	A a;
	B b;
	a.spt1 = &b;
	b.spt2 = &a;
	//将会导致a,b无法正常析构,因为其计数永远大于0;
}

2.确保对象只被一组shared pointer使用;

int *p = new int(4);
shared_ptr<int> sp1(p);
shared_ptr<int> sp2(p);
//会导致sp1,sp2都会在丢失p的拥有权时释放相应的资源(调用delete).
//正确做法如下:
int *p = new int(4);
shared_ptr<int> sp1(p);
shared_ptr<int> sp2(sp1);   //ok

3.deleter的使用,一旦拥有权被转移到一个已拥有过其他对象的shared pointer时候,dleter就会被先前拥有的那个对象所调用(当shared pointer 是最后一个拥有者的时候)。
4.alias 构造函数,

//Alia构造函数,建立一个shared pointer,共享sp2的拥有权,但是指向ptr
shared_ptr<T> sp (sp2, ptr)
//example
class A {int a;};
shared_ptr<A> ptr1(new A);
shared_ptr<int> ptr2(ptr1,&(ptr1->a)); //ptr2指向(ptr1->a)
// 必须确保两对象(A,a)的寿命一致,否则会产生“空荡指针”,或者“资源泄露”;

5.线程安全
当并发访问的是pointer而非其指向的值时

std::shared_ptr<X> global;  //初始化空指针

void foo()
{
	std::shared_ptr<X> local{new X};
	...
	std::atomic_store(&global,local);

6 unique_ptr作为类成员

class A
{
public:
	A() = default;
	~A() = delete;   //不需要了,牛牛牛
private:
	unique_ptr<int> ptr1 = new int5;
	unique_ptr<int[]> ptr1 = new int[5]; //因为delete无法知道删除的是对象还是数组,所以又有一个unique_ptr<T[]>的偏特化版本,重载的operator [],不再提供*和->运算(&p[i]不香吗
结束语
由于smart pointer带来方便的同时也带来了性能损失,这也是为什么c++标准库不是只提供smart pointer的原因。shared_pointer需要一个额外的计数器,weak_ptr同上;unique_ptr可以媲美naive_ptr(其smart体现在特殊的**构造函数**和**析构函数**,如果给定的deleter是stateless或者empty,就不会有额外的内存开销),推荐使用function object(包括lamda)作为deleter,从而实现零开销。
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值