当前位置: 代码迷 >> 综合 >> 【C++】智能指针(二)--unique_ptr、shared_ptr和wear_ptr
  详细解决方案

【C++】智能指针(二)--unique_ptr、shared_ptr和wear_ptr

热度:80   发布时间:2024-01-30 14:09:29.0

unique_ptr

一、unique_ptr的引出
我们知道auto_ptr通过复制构造或者通过赋值后,原来的auto_ptr对象就报废了。所有权转移到新的对象中去了。如果我们不想像auto_ptr那样不知不觉的就让原来的auto_ptr对象失效,这个时候就需要用到unique_ptr指针。
二、unique_ptr的思想
unique_ptr是 C++ 11 提供的用于防止内存泄漏的智能指针中的一种实现,独享被管理对象指针所有权的智能指针。unique_ptr对象包装一个原始指针,并负责其生命周期。当该对象被销毁时,会在其析构函数中删除关联的原始指针。
unique_ptr具有->和*运算符重载符,因此它可以像普通指针一样使用。
三、使用

template<typename T>
class Unique_Ptr
{
public:Unique_Ptr(T* ptr):mptr(ptr){}~Unique_Ptr(){delete mptr;}T* operator->(){return mptr;}T& operator*(){return *mptr;}
private:Unique_Ptr(const Unique_Ptr<T>&);//将拷贝构造函数和赋值运算符函数写在私有下Unique_Ptr<T>& operator=(const Unique_Ptr<T>&);T* mptr;
}
int main()
{Unique_Ptr<int> up1(new int);Unique_Ptr<int> up2(up1);//不允许多个智能指针指向同一个内存块return 0;
}

四、一些特性
1、无法进行复制构造与赋值操作
2、可以进行移动构造和移动赋值操作
3、可做为容器元素
五、可以实现的一些功能

  • 为动态申请的内存提供异常安全
  • 讲动态申请的内存所有权传递给某函数
  • 从某个函数返回动态申请内存的所有权
  • 在容器中保存指针

shared_ptr

一、shared_ptr的引出
如果我们想要多个智能指针对象指向一个堆内存。然后让最后一个销毁的对象释放该堆内存的话就需要用到shared_ptr指针。
二、定义
从名字share就可以看出了资源可以被多个指针共享,它使用计数机制来表明资源被几个指针共享。出了可以通过new来构造,还可以通过传入auto_ptr, unique_ptr,weak_ptr来构造。当我们调用release()时,当前指针会释放资源所有权,计数减一。当计数等于0时,资源会被释放
三、使用

class Ref_Mangement
{
public:Ref_Mangement(){current = 0;}void addRef(void* ptr){int index = FindIndex(ptr);if(index < 0){node[current].addr = ptr;node[current].count = 1;current ++;}else{node[index].count++;}}void delRef(void* mptr){int index = FindIndex(ptr);if(index < 0){throw std::exception("ref is error!");}else{if(getRef() > 0){node[index].cout--;}}}int getRef(void* ptr){int index = FindIndex(ptr);if(index < 0){return -1;}else{return node[ind].count;}}private:int FindIndex(void* ptr)//查询地址对应的下标{for(int i = 0;i < 10; i++){if(node[i].addr == ptr){return i;}}return -1;}class Node{public:Node(void* add,int cnt = 0):addr(add),count(cnt){}public:void* addr;int count;};Node node[10];int current;
};
template<typename T>
class Shared_Ptr
{
public:Shared_Ptr(T* ptr):mptr(ptr){rm.addRef(mptr);}Shared_Ptr(const Shared_Ptr<T>& rhs){mptr = rhs.mptr;rm.addRef(mptr);}Shared_Ptr<T>& operator=(const Shared_Ptr<T>& rhs){if(this != &rhs){rm.delRef(mptr);if(rm.getRef(mptr) == 0){delete mptr;}mptr = rhs.mptr;rm.addRef(mptr);}return *this;}~Shared_Ptr(){rm.delRef(mptr);if(rm.getRef(mptr)==0){delete mptr;}mptr = NULL;}T* operator->(){return mptr;}T& operator*(){return *mptr;}
private:T* mptr;static Ref_Mangement rm;
};
template<typename T>
Ref_Mangement Shared_Ptr<T>::rm;
int main()
{int* p = new int;Shared_Ptr<int> sp1(p);Shared_Ptr<int> sp4(new int);sp2 = sp4;return 0;
}

wear_ptr
是为了解决强智能指针相互引用的问题,而且他不能单独使用.
weak_ptr是用来解决shared_ptr相互引用时的死锁问题,如果说两个shared_ptr相互引用,那么这两个指针的引用计数永远不可能下降为0,资源永远不会释放。它是对对象的一种弱引用,不会增加对象的引用计数,和shared_ptr之间可以相互转化,shared_ptr可以直接赋值给它,它可以通过调用lock函数来获得shared_ptr。
使用

template<typename T>
Ref_Mangement Shared_Ptr<T>::rm;
class B;
class A
{
public:A(){std::cout << "A::A()" << std::endl;}~A(){std::cout << "A::~A()" << std::endl;}
public:Shared_Ptr<B> spa;
};
class B
{
public:B(){std::cout << "B::B()" << std::endl;}~B(){std::cout << "B::~B()" << std::endl;}
public:Shared_Ptr<A> spb;
};
int main()
{Shared_Ptr<A> pa = new A();Shared_Ptr<B> pa = new B();return 0;
}

这个函数运行我们发现是可以调用A和B的构造以及A和B的析构的。
但当我们在主函数中加上这两句代码之后。

pa->spa = pb;
pb->spb = pa;

发现无法调用A和B的析构,如下图所示:
在这里插入图片描述

这就是造成了内存泄漏的问题,也就是强指针相互引用的问题。下面我们来使用弱指针来解决这个问题。
我们只要将代码改成如下就可以调用成功了

template<typename T>
Ref_Mangement Shared_Ptr<T>::rm;
class B;
class A
{
public:A(){std::cout << "A::A()" << std::endl;}~A(){std::cout << "A::~A()" << std::endl;}
public:Weak_Ptr<B> spa;
};
class B
{
public:B(){std::cout << "B::B()" << std::endl;}~B(){std::cout << "B::~B()" << std::endl;}
public:Weak_Ptr<A> spb;
};