513-带引用计数的智能指针

带引用计数的智能指针:shared_ptr和weak_ptr
带引用计数的好处: 多个智能指针可以管理同一个资源。

C++11
boost库的智能指针拿到标准库里面

带引用计数:给每一个对象的资源,匹配一个引用计数
当1个智能指针引用这个资源的时候,这个资源相应的引用计数就加1,当这个智能指针出作用域,不再使用这个资源的时候,这个资源的引用计数就减1。

当引用计数减1不为0的时候,这个智能指针不使用这个资源了,但是还有其他智能指针在使用这个资源,这个智能指针不能析构这个资源,只能直接走人。

当引用计数减1为0的时候,说明当前智能指针是最后使用这个资源的智能指针,所以它要负责这个资源的释放。

模拟实现shared_ptr

引用计数类的实现:
在这里插入图片描述

然后我们给之前定义的智能指针,添加这个成员
在这里插入图片描述

智能指针构造的时候给资源建立引用计数对象
析构的时候也要- -判断
在这里插入图片描述

拷贝构造函数实现如下:
在这里插入图片描述
赋值函数如下:
在这里插入图片描述
现在这样做就可以了
在这里插入图片描述
在这里插入图片描述
多个智能指针管理同一个资源了

template<typename T>
class RefCnt
{
public:
	RefCnt(T* ptr = nullptr)
		:mptr(ptr)
	{
		if (mptr != nullptr)
		{
			mcount = 1;
		}
	}
	void addRef() { mcount++; }
	int  defRef() { return --mcount; }
	void show() { cout << mcount << endl; }
private:
	T* mptr;
	atomic_int mcount;
};

template<typename T>
class CSmartPtr
{
public:
	CSmartPtr(T* p = nullptr)
		:ptr(p)
	{
		mpRefCnt = new RefCnt<T>(ptr);
	}
	~CSmartPtr()
	{
		if (0 == mpRefCnt->defRef())
		{
			delete ptr;
			ptr = nullptr;
		}
	}
	CSmartPtr(const CSmartPtr<T>& src)
		:ptr(src.ptr), mpRefCnt(src.mpRefCnt)
	{
		if (ptr != nullptr)
		{
			mpRefCnt->addRef();
		}
	}
	CSmartPtr<T>& operator=(const CSmartPtr<T>& src)
	{
		if (this == &src)
		{
			return *this;
		}
		if (0 == mpRefCnt->defRef())
		{
			delete ptr;
		}
		ptr = src.ptr;
		mpRefCnt = src.mpRefCnt;
		mpRefCnt->addRef();
		return *this;
	}
	T& operator*()
	{
		return *ptr;
	}
	T* operator->()
	{
		return ptr;
	}
	void Count() { return mpRefCnt->show(); }
private:
	T* ptr;
	RefCnt<T>* mpRefCnt;
};

int main()
{
	CSmartPtr<int>p(new int(50));
	CSmartPtr<int>q(p);
	cout <<*p<< endl;
	cout << *q << endl;
	p.Count();
	cout << p.operator->() << endl;

}

在这里插入图片描述

库里实现的shared_ptr和weak_ptr是线程安全的!

可以直接使用在多线程环境下
库里是用atomic_int定义的
在这里插入图片描述

shared_ptr的交叉引用问题

在这里插入图片描述
弱智能指针观察强智能指针,强智能指针观察资源(内存)

在这里插入图片描述
强智能指针循环引用(交叉引用)是什么问题?什么结果?怎么解决?
在这里插入图片描述
在这里插入图片描述
运行一下
在这里插入图片描述
但是如果我们这么调用呢?
在这里插入图片描述
我们运行一下
在这里插入图片描述
出作用域都是从2减到1,根本达不到析构的条件。
造成对象new出来的资源无法释放,严重的资源泄漏问题。

在这里插入图片描述
如何解决这个问题呢?
在这里插入图片描述
在这里插入图片描述
运行成功
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
弱智能指针只是观察对象是否活着,不改变引用计数

假如说,现在A里面有一个好的方法
在这里插入图片描述
在这里插入图片描述
B中的func函数调用不了A的方法
因为弱智能指针只是1个观察者,只会观察资源,不能去使用资源。
弱智能指针根本没有提供*运算符重载和->运算符重载。

但是我们可以这么用
在这里插入图片描述
在多线程中,弱智能指针观察的资源有可能被释放有可能没有被释放,主要就是根据引用计数是否为0,有可能,弱智能指针需要使用对象,需要从一个观察者提升为强智能指针,在提升的过程中有可能提升失败,资源已经释放了,有可能提升成功,资源还没释放。
在这里插入图片描述在这里插入图片描述
运行成功
在这里插入图片描述

class B;
class A
{
public:
	A() { cout << "A()构造" << endl; }
	~A() { cout << "~A()析构" << endl; }
	weak_ptr<B>ptr2;
	void testA() { cout << "非常好的方法" << endl; }
};
class B
{
public:
	B() { cout << "B()构造" << endl; }
	~B() { cout << "~B()析构" << endl; }
	void func()
	{
		shared_ptr<A>ps = ptr1.lock();
		if (ps != nullptr)
		{
			ps->testA();
		}
		cout << ps.use_count() << endl;//智能指针ps提升成功,引用技术加1到2
		//智能指针ps出函数作用域自动析构,引用计数从2减到1
	}
	weak_ptr<A>ptr1;
};
int main()
{
	shared_ptr<A>ptra(new A());
	shared_ptr<B>ptrb(new B());
	ptra->ptr2 = ptrb;
	ptrb->ptr1 = ptra;
	cout << ptra.use_count() << endl;//1
	cout << ptra.use_count() << endl;//1
	ptrb->func();
	cout << ptra.use_count() << endl;//1
	cout << ptra.use_count() << endl;//1
	ptrb->func();
}

在这里插入图片描述

多线程访问共享对象的线程安全问题

在这里插入图片描述
我们看下面例子
在这里插入图片描述
在这里插入图片描述
运行如下
在这里插入图片描述
A对象就是main线程和子线程共享的对象。

如果我们现在对代码进行修改
在这里插入图片描述
这样合适么?析构了才去访问这个对象的方法,显然,非常不合理!
在这里插入图片描述
析构之后,很可能访问原先的资源已经没有了
在这里插入图片描述
给对象添加引用计数,使用强弱智能指针!
newA的资源由主线程控制,子线程只引用它,这个对象到时候有的话就访问它,没有的话就不访问它的方法。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

智能指针自定义删除器

在这里插入图片描述
并不是说所有资源的释放都是delete指针 进行释放的。
比如说,用智能指针来托管数组的资源,delete就得加个中括号[]了,
如果用智能指针管理的是文件资源,或者是其他资源,释放的方式不是delete。

在这里插入图片描述
这2个智能指针都可以提供自定义删除器。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
先构造的后析构,后构造的先析构
但是这样写很麻烦,要写很多模板类。
我们使用lambda表达式!!!
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是一个引用计数智能指针的类模版的示例代码: ```c++ template<typename T> class SmartPtr { public: SmartPtr() : ptr(nullptr), refCount(new int(0)) {} explicit SmartPtr(T* p) : ptr(p), refCount(new int(1)) {} SmartPtr(const SmartPtr<T>& other) : ptr(other.ptr), refCount(other.refCount) { ++(*refCount); } SmartPtr<T>& operator=(const SmartPtr<T>& other) { if (this != &other) { if (--(*refCount) == 0) { delete ptr; delete refCount; } ptr = other.ptr; refCount = other.refCount; ++(*refCount); } return *this; } ~SmartPtr() { if (--(*refCount) == 0) { delete ptr; delete refCount; } } T& operator*() const { return *ptr; } T* operator->() const { return ptr; } int getRefCount() const { return *refCount; } private: T* ptr; int* refCount; }; ``` 这个类模版定义了一个智能指针类 `SmartPtr`,它可以自动释放各种类对象指针,并且支持引用计数。其中, `ptr` 是指向实际对象的指针, `refCount` 是指向引用计数的指针。 在 `SmartPtr` 的构造函数中,我们将引用计数初始化为 0,表示当前没有任何指针引用该对象。当我们使用 `SmartPtr` 类模版创建一个实例时,我们可以传入一个指向实际对象的指针,此时我们会将引用计数初始化为 1。当我们将这个实例复制给另一个实例时,我们需要增加引用计数。当我们销毁一个实例时,我们需要将引用计数减少,如果引用计数归零,我们需要释放实际对象并销毁引用计数。 以下是一个使用 `SmartPtr` 类模版的例子: ```c++ #include <iostream> #include <string> using namespace std; class Person { public: Person(const string& n) : name(n) { cout << "Person " << name << " is created." << endl; } ~Person() { cout << "Person " << name << " is destroyed." << endl; } void sayHello() { cout << "Hello, I'm " << name << "." << endl; } private: string name; }; int main() { SmartPtr<Person> p1(new Person("Alice")); SmartPtr<Person> p2(new Person("Bob")); SmartPtr<Person> p3(p1); SmartPtr<Person> p4 = p2; cout << p1->getRefCount() << endl; cout << p2->getRefCount() << endl; cout << p3->getRefCount() << endl; cout << p4->getRefCount() << endl; p1 = p2; cout << p1->getRefCount() << endl; cout << p2->getRefCount() << endl; cout << p3->getRefCount() << endl; cout << p4->getRefCount() << endl; return 0; } ``` 在这个例子中,我们定义了一个 `Person` 类,它包含一个字符串类型的名字成员和一个 `sayHello` 方法。我们使用 `SmartPtr` 类模版创建了四个指向 `Person` 对象的智能指针实例,分别为 `p1`、`p2`、`p3` 和 `p4`。在创建 `SmartPtr` 实例时,我们传入了一个指向 `Person` 对象的指针,并且 `SmartPtr` 类模版自动增加了引用计数。 在程序的后面,我们将 `p1` 赋值为 `p2`,此时 `p1` 原本指向的 `Person` 对象将被释放,引用计数减少到 1。我们可以通过调用 `getRefCount` 方法获取当前引用计数的值。最后,我们将所有的 `SmartPtr` 实例销毁,它们所指向的 `Person` 对象也将被自动释放。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林林林ZEYU

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值