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前打印出所有析构函数的输出。

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

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

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-09 06:23:27

C++智能指针的实现的相关文章

智能指针的原理和简单实现

什么是智能指针? 智能指针实质上是一个类,定义一个类来封装资源的分配和释放.这个类的构造函数中传入一个指针,完成资源的分配和初始化.在析构函数中释放传入的该指针,完成资源的释放. 为什么要用智能指针? 智能指针就是智能,自动化的管理指针所指向的动态资源. 例如以下情况:代码中经常会忘记释放动态开辟的内存资源,导致内存泄露. // case1 void Test2() {  int* p1 = new int(2);  bool isEnd = true;  //...  if (isEnd)  

实战c++中的智能指针unique_ptr系列-- 使用std::unique_ptr代替new operator(错误:‘unique_ptr’ is not a member of ‘std’)

写了很多篇关于vector的博客,其实vector很便捷,也很简单.但是很多易错的问题都是vector中的元素为智能指针所引起的.所以决定开始写一写关于智能指针的故事,尤其是unique_ptr指针的故事. 这是个开始,就让我们使用std::unique_ptr代替new operator吧! 还是用程序说话: #include<iostream> int main() { while (true) int *x = new int; } 看下任务管理器中的内存: 此时使用智能指针unique

C++智能指针简单剖析

导读 最近在补看<C++ Primer Plus>第六版,这的确是本好书,其中关于智能指针的章节解析的非常清晰,一解我以前的多处困惑.C++面试过程中,很多面试官都喜欢问智能指针相关的问题,比如你知道哪些智能指针?shared_ptr的设计原理是什么?如果让你自己设计一个智能指针,你如何完成?等等--.而且在看开源的C++项目时,也能随处看到智能指针的影子.这说明智能指针不仅是面试官爱问的题材,更是非常有实用价值. 下面是我在看智能指针时所做的笔记,希望能够解决你对智能指针的一些困扰. 目录

boost智能指针使用

#include <iostream> #include <tr1/memory> #include <boost/scoped_ptr.hpp> //scoped_ptr还不属于tr1 #include <boost/scoped_array.hpp> //scored_array也不属于tr1 #include <boost/shared_array.hpp> //shared_array也不属于tr1 class CTest { publi

webkit智能指针 - RefPtr, PassRefPtr

历史 2005年之前,Webkit中很多对象都采用引用计数的方式.它们通过继承RefCounted]类模板来实现这种模式.RefCounted主要是实现了ref()和deref()两个函数.在需要引用对象时要调用ref()增加引用计数,在不再需要对象时,要调用deref()函数减少引用计数.ref()和deref()需要成对出现.这和使用new/delete一样,多调用.少调用.没调用的问题总是时有发生.如果能由编译器自动完成ref, deref的调用,C/C++编程的bug至少也可以减少一半以

智能指针tr1::shared_ptr、boost::shared_ptr使用

对于tr1::shared_ptr在安装vs同时会自带安装,但是版本较低的不存在.而boost作为tr1的实现品,包含 "Algorithms Broken Compiler Workarounds Concurrent Programming Containers Correctness and Testing Data Structures Domain Specific Function Objects and Higher-order Programming Generic Progra

C++ Primer笔记8_动态内存_智能指针

1.动态内存 C++中,动态内存管理是通过一对运算符完成的:new和delete.C语言中通过malloc与free函数来实现先动态内存的分配与释放.C++中new与delete的实现其实会调用malloc与free. new分配: 分配变量空间: int *a = new int; // 不初始化 int *b = new int(10); //初始化为10 string *str = new string(10, ); 分配数组空间: int *arr = new int[10];//分配的

C++之智能指针20170920

/******************************************************************************************************************/ 一.C++智能指针_自己实现智能指针 1.使用局部变量结合new的方式,防止new导致的内存泄漏 class sp { private: Person *p; public: sp() : p(0) {}//表明sp的构造函数 继承person的无参构造函数 sp(

智能指针简介

智能指针用于解决常规指针所带来的内存泄露.重复释放.野指针等内存问题.智能指针基于这样的事实得以发挥作用:定义在栈中的智能指针,当超出其作用域时,会自动调用它的析构函数,从而可以释放其关联的内存资源. 之前C++标准库中定义的智能指针std::auto_ptr<T>,因其设计存在缺陷,所以已不再推荐使用.C++11引入了新的智能指针:unique_ptr.shared_ptr和weak_ptr. 一:unique_ptr unique_ptr类似于auto_ptr.两个unique_ptr实例

C++智能指针剖析(下)boost::shared_ptr&amp;其他

1. boost::shared_ptr 前面我已经讲解了两个比较简单的智能指针,它们都有各自的优缺点.由于 boost::scoped_ptr 独享所有权,当我们真真需要复制智能指针时,需求便满足不了了,如此我们再引入一个智能指针,专门用于处理复制,参数传递的情况,这便是如下的boost::shared_ptr. boost::shared_ptr 属于 boost 库,定义在 namespace boost 中,包含头文件#include<boost/smart_ptr.hpp> 便可以使