SmartPointer

很久没有写博客了,很多工作中的总结都写在了自己的记事本里,比较杂,也没反映到博客上。刚去引擎组但却由于总公司的决策原因,引擎组当建立3个月就被撤销了,我也就没能继续做引擎了。部门被撤,当前也没任务,这些天就闲着看书。公司最近准备开IOS项目,我也经过很多思想上的挣扎,终于决定接受转向IOS等移动方向。

原因是虽然自己喜欢编程,喜欢做3d引擎,但是机会可遇不可求。能做3d引擎固然好,但是我当前还是个应届毕业生,也没有完整的做过任何商业项目,所以做个新项目也是不屈才的,更何况,新的领域,新的技术是IT行业的未来,如果能在未来领域里占有一席之地,或者要创业,移动都是值得的。

但归根结底,我觉得只要不断学习,做好每件看似简单的事情,不断的做到更好,就一定能让自己成为行业里的一面旗帜。我在做引擎中,首先是负责资源管理的,虽然引擎编程才刚刚开始,但是我对资源管理,特别是更底层的指针管理和内存分配等各种策略都琢磨了琢磨。这些天在看<<Game Engine Atchitecture>>,其中讲到StackMemory方式的分配策略,自己也模仿的实现了一把。

StackMemory方式的分配是首先在程序启动时申请一大块内存,然后其他对象要动态申请的时候,通过重载new操作符,使其在new的时候,转到StackMemory的分配策略(从低地址往高地址不断分配),然后当这个栈内存不需要时,StackMemory会调用所有曾经在它那分配过内存的对象的析构函数,然后将栈顶指针恢复到最低地址。这里讲的很粗糙,很有一些细节和策略需要注意。

通过StackMemory我们能够避免反复的new,delete,因为这些new,delete是很慢的操作(书上是这么说的,我目前相信大师没有骗我),特别是对于游戏软件来说,反复的new,delete必然会是cpu端的一大瓶颈,为了得到高帧率,高效率,我们有必要搞定这个问题。StackMemory只能搞定一小部门问题。

说了很多,其实是想说通过实现StackMemory,我觉得内存管理不错,于是想着解决大型软件中最常见的崩溃问题---野指针访问违例。我们经常将一个new出来的地址给了一个指针,然后这个指针有传给另一个指针,反复传递,等又一次我们想释放这个内存,确导致其他使用该地址的指针访问违例,程序崩溃。当然这个问题是由于结构混乱,导致指针在被销毁后还在访问,但是游戏软件确实太大,很多人参与写代码,光靠大家保持警惕,尽量少犯错时无法彻底避免的。所以我们应该想一个彻底的方法来避免野指针。我记得Torque中就有将指针封装,并串成链表管理的方式,我今天就模仿者写了一个SmartPointer来实现类似的功能。而且由于以前在实习公司看Torque时,对底层的管理很是模糊,所以自己实现一把也是很过瘾,很能够调理自己的。

上面的都算废话了,可以直接略过,主题在下面。

通过先实现一个简单的int*的SmartPointer,然后转换到模板SmartPointer,再反复修改,终于写出了一个简陋的SmartPointer(并且在这个过程中也弥补了自己一些基础知识的遗忘和不牢固)。把这个过程中对SmartPointer的需求列一下:

  1. 具有将指针串成链的功能,且在SmartPointer对象之间赋值时,能将这些SmartPointer隐式的加入到链表中,当SmartPointer对象被析构时应该冲链表中撤出来,并且如果此时链表中就剩这一个了,那么应该销毁SmartPointer所指向的真正的内存。
  2. SmartPointer不同类型的对象的之间应该可以赋值,因为他们虽然类型不同,但是他们存放的数据本身意义是相同的。

以下是我的SmartPointer的代码:

#ifndef __SMARTPOINTER__H__
#define __SMARTPOINTER__H__

template < typename T >
class SmartPointer
{
public:
	SmartPointer() :
		m_Pointer( NULL ),
		m_Next( NULL ),
		m_Prev( NULL )
	{
	}

	explicit SmartPointer( T p ) :
		m_Pointer( p ),
		m_Next( NULL ),
		m_Prev( NULL )
	{
	}

	//////////////////////////////////////////////////////////////////////////for same type SmartPointer,
	SmartPointer( SmartPointer& Another )
	{
		( ( SmartPointer& )( *this ) ) = Another;
	}

	SmartPointer& operator = ( SmartPointer& Another )
	{
		if( this != &Another )
		{
			CheckIn( Another );
		}

		return * this;
	}
	//////////////////////////////////////////////////////////////////////////for different SmartPointer
	template< typename AnotherType >
	SmartPointer( SmartPointer< AnotherType >& Another )
	{
		( ( SmartPointer& )( *this ) ) = ( SmartPointer< T >& )Another;
	}

	template< typename AnotherType >
	SmartPointer operator = ( SmartPointer< AnotherType >& Another )
	{
		return ( ( SmartPointer& )( * this ) ) = ( SmartPointer< T >& )Another;
	}
	//////////////////////////////////////////////////////////////////////////

	~SmartPointer()
	{
		//if this SmartPointer is last SmartPointer in the list, we should destroy the SmartPointer list.
		if( !m_Prev && !m_Next )
		{
			Destroy();
		}//if not, we check this SmartPointer out.
		else
		{
			CheckOut();
		}
	}

	void Destroy()
	{
		delete m_Pointer;
		ClearSmartPointerList();
	}

	T GetPointer()
	{
		return m_Pointer;
	}

protected:
	void CheckOut()
	{
		m_Pointer = NULL;

		if( m_Prev && m_Next )//in the middle
		{
			m_Prev->m_Next = m_Next;
			m_Next->m_Prev = m_Prev;
		}
		else if( m_Prev && !m_Next )//at the tail
		{
			m_Prev->m_Next = NULL;
		}
		else//at the head
		{
			m_Next->m_Prev = NULL;
		}
	}

	void CheckIn( SmartPointer& PrevSmartPointer )
	{
		m_Pointer = PrevSmartPointer.m_Pointer;

		//following invocation order mustn't be changed.

		//things for current SmartPointer
		this->m_Next = PrevSmartPointer.m_Next;
		this->m_Prev = &PrevSmartPointer;

		//things for next SmartPointer if exists.
		if( PrevSmartPointer.m_Next )
		{
			PrevSmartPointer.m_Next->m_Prev = this;
		}

		//things for previous SmartPointer
		PrevSmartPointer.m_Next = this;
	}

	void ClearSmartPointerList()
	{
		SmartPointer* ForwardPointer = m_Prev;
		SmartPointer* BackwardPointer = m_Next;
		SmartPointer* TempPointer = NULL;

		m_Pointer = NULL;
		m_Next = NULL;
		m_Prev = NULL;

		while( ForwardPointer )
		{
			ForwardPointer->m_Pointer = NULL;
			ForwardPointer->m_Next = NULL;

			TempPointer = ForwardPointer->m_Prev;
			ForwardPointer->m_Prev = NULL;
			ForwardPointer = TempPointer;
		}

		while( BackwardPointer )
		{
			BackwardPointer->m_Pointer = NULL;
			BackwardPointer->m_Prev = NULL;

			TempPointer = BackwardPointer->m_Next;
			BackwardPointer->m_Next = NULL;
			BackwardPointer = TempPointer;
		}
	}
protected:
	T m_Pointer;
	SmartPointer* m_Next;
	SmartPointer* m_Prev;
};

#endif

以上代码我经过简单测试通过,以下是我的测试代码:

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hInstancePrev,LPSTR lpszCmdLine,int iShowCmd)
{
	_CrtSetDbgFlag( _CRTDBG_LEAK_CHECK_DF | _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG ) );

	SmartPointer< int* > a( new int );
	SmartPointer< int* > a1 = a;
	{
		SmartPointer< int* > a2;
		a2 = a;
	}
	SmartPointer< int* > a3 = a1;

	a3.Destroy();

	SmartPointer< double* > b( new double );

	SmartPointer< char* > b1 = b;
	SmartPointer< int* > b2;
	b2 = b;
}

在编写SmartPointer过程中让我重新复习了一下对一个类的各种接口的规范以及泛型编程中一些注意事项,当然上面代码可能还会存在问题,还请读者直接指出,让我得以学习。

SmartPointer中用的算法其实只有list一个,所以实现起来并不难(这里就不讲了,上面也有简要注释)。但是很多时候明白看懂和自己做出来所得到的依旧不同,通过这次实践也让我更清晰底层的一些功能需求和学习了一些可能的实现方法。

通过看书,从大师那得知SmartPointer并不是一个很好的解决野指针的方法,他推荐boost库中的handle,我没用过。希望以后能见识见识。

时间: 2024-10-01 03:39:21

SmartPointer的相关文章

6.Boost之smartpointer

 1自己实现一个智能指针的功能 #include <iostream> #include <string> #include <vector> #include <algorithm> #include <functional> #include <stdlib.h>   using namespace std;   template<class T> class pmy { public:     pmy()    

VC操作XML编程实例

xml|编程 XML编程实例 文章正文 前段时间,由于工作的需要,利用到了XML,所以对其进行了一些简单的研究.在此愿把一些心得写出来,与各位分享,不对的地方还望多多包涵. 1.什么是 XML? 首先,我想各位应该都已经大概知道什么是XML了.如果,你对什么是XML还没有一个概念的话,你可以看一些相关的材料,我就不多说了. 2.为什么要用XML? 其实,刚开始我也不是很明白,后来在工作中才慢慢意识到.首先,我写的程序需要传送很多的数据结构,比如表格,目录树等等.要在以往,我想自己会去定义一个数据

XML编程实例

xml|编程   前   1.什么是 XML?    首先,我想各位应该都已经大概知道什么是XML了.如果,你对什么是XML还没有一个概念的话,你可以看一些相关的材料,我就不多说了.      2.为什么要用XML?    首先,写的程序需要传送很多的数据结构,比如表格,目录树等等.要在以往,我想自己会去定义一个数据结构.这是相当麻烦的一件事情,而且当这个结构需要不断更新,有很大的灵活性时,那就更让人头疼了,更别说通用性和跨平台了.这时候,XML对树形结构数据的强大表达能力就显示出来了.比如一个

More Effective C++之智能指针

智能指针具有非常强大的能力,谨慎而明智的选择能带来极大的好处.我不否认智能指针的能力,虽然我在之前的否认过auto_ptr.可能由于我自身能力的限制,体会不到auto_ptr的好处,但这样的可能性我觉得已经不大了.但auto_ptr是最简单的智能指针,在它的周围存在大量的作品,这些作品包括Boost.Loki.ACE等等,但是可惜的是目前没有一个我能够说我很熟悉,那么本篇只是作为一个入门,在此基础上,应当阅读Boost.Loki.ACE相关源码. Smart Pointer的核心是实现 temp

【C/C++学院】0904-boost智能指针/boost多线程锁定/哈希库/正则表达式

boost_array_bind_fun_ref Array.cpp #include<boost/array.hpp> #include <iostream> #include <string> using namespace std; using namespace boost; void mainA () { array <int, 5> barray = { 1, 2, 3, 4, 5 }; barray[0] = 10; barray.at(4)

ubuntu-Linux 下编译C出错(windows编译正常)

问题描述 Linux 下编译C出错(windows编译正常) Ubuntu 15 gcc version 5.2.1 错误: scritpt.hpp下是一个 命名空间 namespace script{ .... int setData( PyObject * pObj, Vector4 & rVal, const char * varName = "" ); int setData( PyObject * pObj, Matrix & rVal, const char

C++内存管理学习笔记(5)

/****************************************************************/ /*            学习是合作和分享式的! /* Author:Atlas                    Email:wdzxl198@163.com  /*  转载请注明本文出处: *   http://blog.csdn.net/wdzxl198/article/details/9112123 /************************

C++内存管理学习笔记(4)

/****************************************************************/ /*            学习是合作和分享式的! /* Author:Atlas                    Email:wdzxl198@163.com    /*  转载请注明本文出处: *   http://blog.csdn.net/wdzxl198/article/details/9094793 /**********************

C++中智能指针如何设计和使用_C 语言

     智能指针(smart pointer)是存储指向动态分配(堆)对象指针的类,用于生存期控制,能够确保自动正确的销毁动态分配的对象,防止内存泄露.它的一种通用实现技术是使用引用计数(reference count).智能指针类将一个计数器与类指向的对象相关联,引用计数跟踪该类有多少个对象共享同一指针.每次创建类的新对象时,初始化指针并将引用计数置为1:当对象作为另一对象的副本而创建时,拷贝构造函数拷贝指针并增加与之相应的引用计数:对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用