簡単なshared_ptrを実装してみた

なんか流行ってるらしいし、久しぶりにC++な趣味のコーディングしたかったので、一部機能を省いた簡単なshared_ptrを実装してみた(もちろんスレッドアンセーフ)。shared_ptrの挙動って確かこんなんだっけ……。


shared_ptr.h

#ifndef _YUYARIN_SHARED_PTR_H
#define _YUYARIN_SHARED_PTR_H

namespace yuyarin
{

template<typename Tp>
class ref_count
{
public:
	// default constructor
	ref_count(void)
	:	m_ptr(NULL), m_count(0)
	{
	}
	
	// normal constructor
	ref_count(Tp* ptr)
	:	m_ptr(ptr), m_count(1)
	{
	}
	
	// destructor
	~ref_count(void)
	{
		delete m_ptr;
	}
	
	
	// add reference: count up
	void add(void)
	{
		m_count++;
	}
	
	// release reference: count down and if count is 0, then delete oneself.
	void release(void)
	{
		m_count--;
		if(m_count==0)
		{
			delete this;
		}
	}
	
	// for debug
	unsigned int refcount(void)
	{
		return m_count;
	}
	
private:
	
	Tp* m_ptr;
	unsigned int m_count;
	
}; // end of class ref_count


template<typename Tp>
class shared_ptr
{
public:
	// default constructor
	shared_ptr(void)
	:	m_ptr(NULL), m_pref_count(NULL)
	{
	}
	
	// normal constructor
	explicit shared_ptr(Tp* ptr)
	:	m_ptr(ptr), m_pref_count(NULL)
	{
		m_pref_count = new ref_count<Tp>(ptr);
	}
	
	// copy constructor
	shared_ptr(const shared_ptr<Tp> &sp)
	:	m_ptr(sp.m_ptr)
	{
		sp.m_pref_count->add();
		m_pref_count = sp.m_pref_count;
	}
	
	// destructor
	~shared_ptr()
	{
		m_pref_count->release();
	}
	
	// assignment
	shared_ptr& operator=(const shared_ptr &sp)
	{
		if(m_pref_count!=NULL)
		{
			m_pref_count->release();
		}
		if(sp.m_pref_count!=NULL)
		{
			sp.m_pref_count->add();
		}
		m_ptr = sp.m_ptr;
		m_pref_count = sp.m_pref_count;
		
		return *this;
	}
	
	// get reference(not allowed NULL pointer)
	Tp& operator*() const
	{
		if(m_ptr==0)
		{
			//error
		}
		return *m_ptr;
	}
	
	// get pointer(not allowed NULL pointer)
	Tp* operator->() const
	{
		if(m_ptr==0)
		{
			//error
		}
		return m_ptr;
	}
	
	// get pointer
	Tp* get() const
	{
		return m_ptr;
	}
	
	// for debug
	unsigned int refcount(void)
	{
		return m_pref_count->refcount();
	}
	
private:
	
	Tp* m_ptr;
	ref_count<Tp>* m_pref_count;
	
}; // end of class shared_ptr

} // end of namespace yuyarin

#endif // !_YUYARIN_SHARED_PTR_H

shared_ptr_test.cpp

#include <iostream>
#include "shared_ptr.h"

class TestObject
{
public:
	TestObject(void)
	{
		std::cout << "construct " << this << std::endl;
	}
	
	~TestObject(void)
	{
		std::cout << "destruct " << this << std::endl;
	}
	
	void greet(void)
	{
		std::cout << "Hello!! I'm " << this << std::endl;
	}
};
typedef yuyarin::shared_ptr<TestObject> p;

template<typename T>
void print(T s)
{
	std::cout << s << std::endl;
}

void func(p ptrX)
{
	p ptrY = ptrX;
	print(ptrX.refcount());
	print(ptrY.refcount());
}

int main(void)
{
	{
		p ptr1(new TestObject());//construct
		print(ptr1.refcount());//1
		ptr1->greet();
		ptr1.get()->greet();
		(*ptr1).greet();
		
		p ptr2 = ptr1;
		print(ptr1.refcount());//2
		print(ptr2.refcount());//2
		
		// scope
		print("enter a scope");
		{
			p ptr3 = ptr1;
			print(ptr1.refcount());//3
			print(ptr2.refcount());//3
			print(ptr3.refcount());//3
			
			ptr1 = ptr3;
			print(ptr1.refcount());//3
			print(ptr2.refcount());//3
			print(ptr3.refcount());//3
		}
		print("left the scope");
		
		print(ptr1.refcount());//2
		print(ptr2.refcount());//2
		
		print("enter a function");
		func(ptr1);
		// 4
		// 4
		print("left the function");
		
		print(ptr1.refcount());//2
		
		p ptr4(new TestObject());//construct
		ptr2 = ptr4;
		print(ptr1.refcount());//1
		print(ptr2.refcount());//2
		print(ptr4.refcount());//2
		
		p ptr5(new TestObject());//construct
		ptr5 = ptr1;// destruct
		print(ptr1.refcount());//2
		print(ptr5.refcount());//2
		// destruct
		// destruct
	}
	print("out of scope");
}

result

construct 00931B10
1
Hello!! I'm 00931B10
Hello!! I'm 00931B10
Hello!! I'm 00931B10
2
2
enter a scope
3
3
3
3
3
3
left the scope
2
2
enter a function
4
4
left the function
2
construct 00931B48
1
2
2
construct 00931B68
destruct 00931B68
2
2
destruct 00931B48
destruct 00931B10
out of scope

なんだかんだで一時間以上かけてしまった……。