SmartPointer

简介: 很久没有写博客了,很多工作中的总结都写在了自己的记事本里,比较杂,也没反映到博客上。刚去引擎组但却由于总公司的决策原因,引擎组当建立3个月就被撤销了,我也就没能继续做引擎了。

很久没有写博客了,很多工作中的总结都写在了自己的记事本里,比较杂,也没反映到博客上。刚去引擎组但却由于总公司的决策原因,引擎组当建立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,我没用过。希望以后能见识见识。

相关文章
|
11天前
|
Kubernetes 安全 Devops
【云效流水线 Flow 测评】驾驭云海:五大场景下的云效Flow实战部署评测
云效是一款企业级持续集成和持续交付工具,提供免费、高可用的服务,集成阿里云多种服务,支持蓝绿、分批、金丝雀等发布策略。其亮点包括快速定位问题、节省维护成本、丰富的企业级特性及与团队协作的契合。基础版和高级版分别针对小型企业和大规模团队,提供不同功能和服务。此外,云效对比Jenkins在集成阿里云服务和易用性上有优势。通过实战演示了云效在ECS和K8s上的快速部署流程,以及代码质量检测和AI智能排查功能,展示了其在DevOps流程中的高效和便捷,适合不同规模的企业使用。本文撰写用时5小时,请各位看官帮忙多多支持,如有建议也请一并给出,您的建议能帮助我下一篇更加出色。
136092 13
|
15天前
|
存储 Prometheus 并行计算
10倍性能提升-SLS Prometheus 时序存储技术演进
本文将介绍近期SLS Prometheus存储引擎的技术更新,在兼容 PromQL 的基础上实现 10 倍以上的性能提升。同时技术升级带来的成本红利也将回馈给使用SLS 时序引擎的上万内外部客户。
158389 7
|
12天前
|
NoSQL API Redis
最佳实践|如何使用c++开发redis module
本文将试着总结Tair用c++开发redis module中遇到的一些问题并沉淀为最佳实践,希望对redis module的使用者和开发者带来一些帮助(部分最佳实践也适用于c和其他语言)。
76200 0
|
11天前
|
存储 SQL Apache
阿里云数据库内核 Apache Doris 基于 Workload Group 的负载隔离能力解读
阿里云数据库内核 Apache Doris 基于 Workload Group 的负载隔离能力解读
阿里云数据库内核 Apache Doris 基于 Workload Group 的负载隔离能力解读
|
16天前
|
人工智能 弹性计算 算法
一文解读:阿里云AI基础设施的演进与挑战
对于如何更好地释放云上性能助力AIGC应用创新?“阿里云弹性计算为云上客户提供了ECS GPU DeepGPU增强工具包,帮助用户在云上高效地构建AI训练和AI推理基础设施,从而提高算力利用效率。”李鹏介绍到。目前,阿里云ECS DeepGPU已经帮助众多客户实现性能的大幅提升。其中,LLM微调训练场景下性能最高可提升80%,Stable Difussion推理场景下性能最高可提升60%。
|
12天前
|
存储 弹性计算 Cloud Native
1 名工程师轻松管理 20 个工作流,创业企业用 Serverless 让数据处理流程提效
为应对挑战,语势科技采用云工作流CloudFlow和函数计算FC,实现数据处理流程的高效管理与弹性伸缩,提升整体研发效能。
64682 1
|
18天前
|
消息中间件 安全 API
Apache RocketMQ ACL 2.0 全新升级
RocketMQ ACL 2.0 不管是在模型设计、可扩展性方面,还是安全性和性能方面都进行了全新的升级。旨在能够为用户提供精细化的访问控制,同时,简化权限的配置流程。欢迎大家尝试体验新版本,并应用在生产环境中。
187453 6
|
2天前
|
关系型数据库 Serverless 分布式数据库
高峰无忧,探索PolarDB PG版Serverless的弹性魅力
在数字经济时代,数据库成为企业命脉,面对爆炸式增长的数据,企业面临管理挑战。云原生和Serverless技术革新数据库领域,PolarDB PG Serverless作为阿里云的云原生数据库解决方案,融合Serverless与PostgreSQL,实现自动弹性扩展,按需计费,降低运维成本。它通过计算与存储分离技术,提供高可用性、灾备策略和简化运维。PolarDB PG Serverless智能应变业务峰值,实时监控与调整资源,确保性能稳定。通过免费体验,用户可观察其弹性性能和价格力,感受技术优势。
|
14天前
|
存储 关系型数据库 数据库
|
21天前
|
物联网 PyTorch 测试技术
手把手教你捏一个自己的Agent
Modelscope AgentFabric是一个基于ModelScope-Agent的交互式智能体应用,用于方便地创建针对各种现实应用量身定制智能体,目前已经在生产级别落地。