智能指针——2(unique_ptr唯一性智能指针和shared_ptr共享性智能指针)

目录

1.unique_ptr:

1.1.拷贝构造和赋值语句:

 1.2.删除一个对象和一组对象:

2.shared_ptr:

2.1.构成:

2.2简单实现和内存分布:

2.3拷贝构造和赋值语句:

2.4共享性智能指针的缺点:


1.unique_ptr:

1.1.拷贝构造和赋值语句:

在unique_ptr里因为其所有权的唯一性,拷贝构造和赋值语句会被删除。但是可以进行移动构造和移动赋值。

 还要注意的一点是在调用函数时,因为传参时调用拷贝构造函数,可能传参出现错误。

 1.2.删除一个对象和一组对象:

unique_ptr提供两个模板,一个针对一个对象,一个针对一组对象。

2.shared_ptr:

2.1.构成:

shared_ptr多出一个结构引用计数,用于计算该对象被多少指针对象拥有。可用use_cout计算。

2.2简单实现和内存分布:

template<class _Ty>
class RefCnt
{
private:
	_Ty* mptr;
	int ref;
public:
	RefCnt(_Ty* p = nullptr) :mptr(p), ref(mptr != nullptr)
	{

	}
	~RefCnt() {}
};
template<class _Ty, class _Dx= MyDeletor<_Ty>>//_Dx是删除器
class my_shared_ptr
{
public:
	my_shared_ptr(_Ty* p = nullptr) : ptr(nullptr)
	{
		if (p != nullptr)
		{
			ptr = new RefCnt(p);
		}
	}
	~my_shared_ptr()
	{
		if (ptr != nullptr && --ptr->ref == 0)
		{
			mDeletor(ptr->mptr);
		}
		ptr = nullptr;
	}
private:
	_Ty*          _Ptr;
	
	_Dx mDeletor;
}
class Object
{
private:
	int value;
public:
	Object(int x = 0) :value(x) {};
	~Object() {};
}
int main()
{ 
  my_shared_ptr<Object>op1(new Object(10));
}

内存分布:

2.3拷贝构造和赋值语句:

拷贝构造和赋值语句都是指向同一块RefCnt,并使其引用计数+1.

这里边最难的应该就是移动赋值。在移动赋值时,先确定取出自赋值。如果this指针的指向和s的指向相同,即两个指向同一个RefCnt,那么移动赋值就只是把该计数-1,并把s置空。如果ptr->ref=1,并且不为空,所以在清空ptr时,会直接调用删除器删除对象。最后就是正常的赋值,和清空s.ptr.

    //拷贝构造
   my_shared_ptr(const my_shared_ptr& s)
	{
		if (ptr != nullptr)
		{
			s.ptr = ptr;
			ptr->ref += 1;
		}
	}
    //移动构造
   my_shared_ptr(my_shared_ptr&& s)
	{
		if (ptr != nullptr)
		{
			ptr = s.ptr;

			s.ptr = nullptr;
		}
	}
    //赋值语句
   my_shared_ptr& operator=(my_shared_ptr& s)
	{
		if (this == &s || ptr == s.ptr)return *this;
		if (ptr != nullptr && --ptr->ref == 0)
		{
			mDeletor(ptr);
		}
		ptr = s.ptr;
		if (ptr != nullptr)
		{
			ptr->ref += 1;
		}
		return *this;
	}
    //移动赋值
   my_shared_ptr& operator=(my_shared_ptr&& s)
	{
		if (this == &s)return *this;
		if (ptr == s.ptr && ptr != nullptr && s.ptr != nullptr)
		{
			ptr->ref -= 1;
			s.ptr = nullptr;
			return *this;
		}
		if (ptr != nullptr && --ptr->ref == 0)
		{
			mDeletor(ptr);
		}
		ptr = s.ptr;

		s.ptr = nullptr;
		return *this;
	}

2.4共享性智能指针的缺点:

(1)共享性智能指针在多线程中不安全,因为它引用计数不是原子操作,可以优化为原子操作

(2)共享性智能指针相互引用会造成无法释放。

#include<iostream>

#include<memory>

using namespace std;

class Child;
class Parent
{
public:
	shared_ptr<Child>child;
	Parent() { cout << "Create Parent"; }
	~Parent() { cout << "Destory Parent"; }
	void hi() { cout << "hello"; }
};
class Child
{
public:
	shared_ptr<Parent>parent;
	Child() { cout << "Create Child"; }
	~Child() { cout << "Destory Child"; }

};
int main()
{
	shared_ptr<Parent>p = make_shared<Parent>();
	shared_ptr<Child>c = make_shared<Child>();
	p->child = c;
	c->parent = p;
	c->parent->hi();
	return 0;
}

此时的内存分配:

 Parent对象在建立时,ref=1,Child同理,ref=1。当Parent中child指向Child后,ref+1=2。Child同理。在生存期结束时,ref最后等于1,不能析构。

 

 只有建立没有析构,解决方法就是使用weak_ptr。

#include<iostream>
#include<memory>

using namespace std;

class Child;
class Parent
{
public:
	weak_ptr<Child>child;
	Parent() { cout << "Create Parent"<<endl; }
	~Parent() { cout << "Destory Parent" << endl; }
	void hi() { cout << "hello"<<endl; }
};
class Child
{
public:
	weak_ptr<Parent>parent;
	Child() { cout << "Create Child" << endl; }
	~Child() { cout << "Destory Child" << endl; }

};
int main()
{
	shared_ptr<Parent>p = make_shared<Parent>();
	shared_ptr<Child>c = make_shared<Child>();
	p->child = c;
	c->parent = p;
	p->hi();
	return 0;
}

 后便会详细接收为什么使用weak_ptr可以解决shared_ptr的相互引用问题。

猜你喜欢

转载自blog.csdn.net/weixin_57133901/article/details/125653465
今日推荐