C++智能指针的实现

简介:

说起智能指针,不少人都不陌生。比方auto_ptr、shared_ptr、unique_ptr、weak_ptr。

依据shared_ptr的功能,自己仿造也实现了个。


对于shared_ptr这样的智能指针,有一个共享的引用计数器来控制指针对象的销毁,当引用计数器变为0时。则销毁指针指向的对象。对于多线程安全问题,我在代码中使用的Interlocked系列的原子操作函数。


在学习过程中,渐渐学会了RAII(Resource Acquisition Is Initialization),慢慢领略到了这样的模式的优点。

直接上代码:

SmartPtr.hpp

#pragma once
#include "stdafx.h"
#include <assert.h>
#include <windows.h>

//#define DEBUG_SMARTPTR

template<typename T>
class SmartPtr;

template <typename T>
class RefPtr
{
	friend class SmartPtr<T>;
	explicit RefPtr(T *p) :pointer(p), nUse(0)
	{	
		assert(pointer);
#ifdef DEBUG_SMARTPTR
		std::cout << "Create Pointer!" << std::endl;
#endif
	}

	RefPtr(const RefPtr&)
	{

	}

	RefPtr& operator= (const RefPtr & ref)
	{

	}

	~RefPtr()
	{
#ifdef DEBUG_SMARTPTR
		std::cout << "Delete Pointer!" << std::endl;
#endif
		assert(pointer);
		if (pointer != NULL)
		{
			delete pointer;
			pointer = NULL;
		}	
	}

	unsigned int AddRefCount()
	{
		return InterlockedIncrement((unsigned int*)&nUse);
	}

	unsigned int SubRefCount()
	{
		return InterlockedDecrement((unsigned int*)&nUse);
	}

	bool AddRefCount_lock()
	{
		for (;;)
		{
			unsigned int temp = nUse;
			if (temp == 0)
			{
				return false;
			}
			if (InterlockedCompareExchange((unsigned int *)&nUse, temp + 1, temp) == temp)
			{
				return true;
			}
		}		
	}

	volatile unsigned int nUse;
	T *pointer;
};

template<typename T>
class SmartPtr
{
public:
	explicit SmartPtr(T *pointer) :ptr(new RefPtr<T>(pointer))
	{
		assert(pointer);
#ifdef DEBUG_SMARTPTR
		std::cout << "Create SmartPointer!" << std::endl;
#endif
		ptr->AddRefCount();
	}

	explicit SmartPtr(const SmartPtr<T>& sp) :ptr(sp.ptr)
	{
#ifdef DEBUG_SMARTPTR
		std::cout << "Copy0 SmartPointer!" << std::endl;
#endif
		ptr->AddRefCount();
	}

	explicit SmartPtr(const SmartPtr<T>* sp) :ptr(sp->ptr)
	{
#ifdef DEBUG_SMARTPTR
		std::cout << "Copy1 SmartPointer!" << std::endl;
#endif
		ptr->AddRefCount();
	}

	SmartPtr& operator=(const SmartPtr<T>& sp)
	{
		if (sp.ptr != ptr)
		{
			//注意先加后减,防止指向同对象析构的问题
			if (sp.ptr->AddRefCount_lock())
			{
				if (ptr->SubRefCount() == 0)
				{
					delete ptr;
				}
				ptr = sp.ptr;
			}
		}
#ifdef DEBUG_SMARTPTR
		std::cout << "Copy2 SmartPointer!" << std::endl;
#endif
		return *this;
	}

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

	T* operator->() const
	{
		return GetPtr();
	}

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

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

	bool operator!()
	{
		return !ptr;
	}

	~SmartPtr()
	{
		if (ptr->SubRefCount() == 0)
		{
			delete ptr;
		}
#ifdef DEBUG_SMARTPTR
		std::cout << "Delete SmartPointer!" << std::endl;
#endif
	}

	int GetRefCount() const
	{
		return ptr->nUse;
	}

	bool isNull()
	{
		return ptr->pointer == NULL;
	}

	T* GetPtr() const
	{
		assert(ptr->pointer);
		return ptr->pointer;
	}

	//返回对象
	T GetValue() const
	{
		assert(ptr->pointer);
		return *ptr->pointer;
	}

private:
	RefPtr<T> *ptr;
};

//兼容const比較
template<typename T>
inline bool operator==(const SmartPtr<T>& a,const SmartPtr<T>& b)
{
	return a.GetPtr() == b.GetPtr();
}
template<typename T>
inline bool operator!=(const SmartPtr<T>& a,const SmartPtr<T>& b)
{
	return a.GetPtr() != b.GetPtr();
}
test.cpp

#include "SmartPtr.hpp"
#include <iostream>
#include <process.h>


#define THREADCOUNT 10

typedef struct _PERSON_
{
	char szName[20];
	int nAge;
	~_PERSON_()
	{
		std::cout << "Person Distructor!"<< std::endl;
	}
}PERSON;

SmartPtr<PERSON> g_p(new PERSON{ "g_test", 12 });

unsigned int __stdcall testThread(void *pParam)
{
	SmartPtr<PERSON> sp((SmartPtr<PERSON> *)pParam);
	g_p = sp;
	std::cout << sp->nAge << std::endl;
	return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
	do 
	{
		HANDLE hThread[THREADCOUNT];
		SmartPtr<PERSON> p0(new PERSON{ "Jovi", 12 });
		SmartPtr<PERSON> p1(new PERSON{ "Solanin", 13 });

		SmartPtr<PERSON> p2(p1);
		const SmartPtr<PERSON> p3(p1);

		SmartPtr<PERSON> p4(p3);
		std::cout << (p3 == p1) << std::endl;
		std::cout << (p2 == p0) << std::endl;
		std::cout << (p3 != p1) << std::endl;
		std::cout << (p2 != p0) << std::endl;
		p4 = p0;
		SmartPtr<PERSON> *p = new SmartPtr<PERSON>(p1);
		for (int i = 0; i < THREADCOUNT; i++)
		{
			hThread[i] = (HANDLE)_beginthreadex(NULL, 0, testThread, (void *)p, 0, 0);
//			WaitForSingleObject(hThread[i], INFINITE);
		}
		WaitForMultipleObjects(THREADCOUNT, hThread, TRUE, INFINITE);
		delete p;
	} while (0);

	system("pause");
	return 0;
}
此处的do while(0)仅仅是我想在pause前打印出全部析构函数的输出。


对于基于引用计数器的智能指针,最致命缺点就是循环引用,导致对象被长期占用,无法释放。

以上是我对智能指针的实现和个人看法,如有不对的地方,欢迎指出。





本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/5157999.html,如需转载请自行联系原作者

相关文章
|
1月前
|
C++
【C++】智能指针
【C++】智能指针
|
15天前
|
C++
C++(十八)Smart Pointer 智能指针简介
智能指针是C++中用于管理动态分配内存的一种机制,通过自动释放不再使用的内存来防止内存泄漏。`auto_ptr`是早期的一种实现,但已被`shared_ptr`和`weak_ptr`取代。这些智能指针基于RAII(Resource Acquisition Is Initialization)原则,即资源获取即初始化。RAII确保对象在其生命周期结束时自动释放资源。通过重载`*`和`-&gt;`运算符,可以方便地访问和操作智能指针所指向的对象。
|
15天前
|
C++
C++(九)this指针
`this`指针是系统在创建对象时默认生成的,用于指向当前对象,便于使用。其特性包括:指向当前对象,适用于所有成员函数但不适用于初始化列表;作为隐含参数传递,不影响对象大小;类型为`ClassName* const`,指向不可变。`this`的作用在于避免参数与成员变量重名,并支持多重串联调用。例如,在`Stu`类中,通过`this-&gt;name`和`this-&gt;age`明确区分局部变量与成员变量,同时支持链式调用如`s.growUp().growUp()`。
|
27天前
|
存储 安全 C++
C++:指针引用普通变量适用场景
指针和引用都是C++提供的强大工具,它们在不同的场景下发挥着不可或缺的作用。了解两者的特点及适用场景,可以帮助开发者编写出更加高效、可读性更强的代码。在实际开发中,合理选择使用指针或引用是提高编程技巧的关键。
23 1
|
1月前
|
安全 NoSQL Redis
C++新特性-智能指针
C++新特性-智能指针
|
1月前
|
编译器 C++
virtual类的使用方法问题之在C++中获取对象的vptr(虚拟表指针)如何解决
virtual类的使用方法问题之在C++中获取对象的vptr(虚拟表指针)如何解决
|
30天前
|
存储 C++
c++学习笔记06 指针
C++指针的详细学习笔记06,涵盖了指针的定义、使用、内存占用、空指针和野指针的概念,以及指针与数组、函数的关系和使用技巧。
29 0
|
1月前
|
安全 编译器 容器
C++STL容器和智能指针
C++STL容器和智能指针
|
1月前
|
C++
C++通过文件指针获取文件大小
C++通过文件指针获取文件大小
24 0
|
1月前
|
编译器 C语言 C++
【C++关键字】指针空值nullptr(C++11)
【C++关键字】指针空值nullptr(C++11)