智能指针

270 阅读3分钟
  1. 本文抄袭

    1. 智能指针详细解析(智能指针的使用,原理分析) - 知乎 (zhihu.com)
    2. C++智能指针 shared_ptr 精简 教程_shared_ptr可以用delete吗-CSDN博客
    3. C++ 之构造函数(拷贝/复制构造函数)_复制构造函数和拷贝构造函数-CSDN博客
  2. RAll

    1. RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源(如内存、文件句柄、网络连接、互斥量等等)的简单技术。
    2. 在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,最后在对象析构的时候释放资源。借此,我们实际上把管理一份资源的责任托管给了一个对象。这种做法有两大好处:
      1. 不需要显式地释放资源。
      2. 采用这种方式,对象所需的资源在其生命期内始终保持有效。
  3. 智能指针概念

    1. 智能指针本质就是一个类模板,它可以创建任意的类型的指针对象,当智能指针对象使用完后,对象就会自动调用析构函数去释放该指针所指向的空间。
  4. shared_ptr使用注意

    1. 不要把一个原生指针给多个shared_ptr管理;
    2. 不要把this指针给shared_ptr;
    3. 不要在函数实参里创建shared_ptr;
    4. 不要不加思考地把指针替换为shared_ptr来防止内存泄漏,shared_ptr并不是万能的,而且使用它们的话也是需要一定的开销的;
    5. 环状的链式结构shared_ptr将会导致内存泄漏(可以结合weak_ptr来解决);
    6. 共享拥有权的对象一般比限定作用域的对象生存更久,从而将导致更高的平均资源使用时间;
    7. 在多线程环境中使用共享指针的代价非常大,这是因为你需要避免关于引用计数的数据竞争;
    8. 共享对象的析构器不会在预期的时间执行;
    9. 不使用相同的内置指针值初始化(或reset)多个智能指针;
    10. 不delete get()返回的指针;
    11. 不使用get()初始化或reset另一个智能指针;
    12. 如果使用get()返回的指针,记住当最后一个对应的智能指针销毁后,你的指针就变为无效了;
    13. 如果你使用智能指针管理的资源不是new分配的内存,记住传递给它一个删除器。
  5. 智能指针shared_ptr的应用场景

    1. 有多个使用者共同使用同一个对象,而这个对象没有一个明确的拥有者
    2. 某一个对象的复制操作很费时.
    3. 要把指针存入标准库容器.
    4. 当管理需要特殊清除方式的资源时,可以通过定制shared_ptr的删除器来实现.
  6. 共享指针实现

#include <mutex>
using namespace std;

template<class T>
class shared_ptr {
public:
	shared_ptr(T* _ptr) :ptr(_ptr) 
	{
		ptrcount = new int(1);
		mt = new mutex;
	}

	void AddCount()
	{
		mt->lock();
		(*ptrcount)++;
		mt->unlock();
	}

	shared_ptr(shared_ptr<T>& sp)
		:ptr(sp.ptr)
		,ptrcount(sp.ptrcount)
		,mt(sp.mt)
	{
		AddCount();
	}

	shared_ptr<T&> operator=(const shared_ptr<T>& sp)
	{
		if (sp.ptr ~= ptr)
		{
			Release();
			ptr = sp.ptr;
			ptrcount = sp.ptrcount;
			mt = sp.mt;
			AddCount();
		}

		return *this;
	}

	~shared_ptr()
	{
		Release();
	}

	int& use_count()
	{
		return *ptrcount;
	}

	void Release()
	{
		bool deleteflag = false;
		mt->lock();
		if (--(*ptrcount) == 0)
		{
			delete ptrcount;
			delete ptr;
			ptrcount = nullptr;
			ptr = nullptr;
			deleteflag = true;
		}
		mt->unlock();
		if (deleteflag == true)
		{
			delete mt;
			mt = nullptr;
		}
	}

	T& operator*() 
	{
		return *ptr;
	}

	T* operator->() {
		return ptr;
	}

private:
	T* ptr;
	int* ptrcount;
	mutex* mt;
};