野指针的判别 - 学自另一个项目组

在一次讲座中,项目组同事分享了处理野指针的方法——使用内存池代替std::shared_ptr,以避免高并发时智能指针的锁竞争问题。尽管有人提出疑问是否可以使用weak_ptr,但内存池在运行时表现出的高效率得到了认可。讲解中提到了PoolManaged和PoolPtr两个模板,分别用于Player和Pet的内存管理。
摘要由CSDN通过智能技术生成

公司另一个项目组的同事,昨天做了讲座:一个野指针的处理方案。

先看一个典型的野指针:

#include <iostream>
#include <string>

using namespace std;

//===========================================================
class Player
{
	string	_name;

public:
	Player(const string& name)
		:_name(name)
	{
	}

	const string& Name() const 
	{
		return _name; 
	}
};

//===========================================================
class Pet
{
	string		_name;
	Player*		_player;

public:
	Pet(const string& name, Player* player)
		:_name(name)
		,_player(player)
	{
	}

	void Update()
	{
		cout << _name << " loves " << _player->Name() << "!\n";
	}
};

//===========================================================
int main()
{
	Player* tom = new Player("Tom");
	Pet* pet = new Pet("Luna", tom);

	pet->Update();

	delete tom;
	pet->Update();

	//-------------------------------
	cout <<"------- Done -------";
	cin.get();
	return 0;
}

Tom析构后,pet中就剩下了野指针,它访问的是已经回收的内存。

该同事介绍的方案是“内存池”,用以代替std::shared_ptr。用他的话说,智能指针会加锁,所以在高并发的时候会产生瓶颈。(我有疑问:这种情况下,不是应该用weak_ptr吗?weak_ptr不会加锁吧?)

内存池的方案果然不错,在运行时效率很高。看下面的代码:

poolmgr.h 该文件定义了两个模板:

  • PoolManaged用于包装Player,把Player的内存管理权交于池。
  • PoolPtr用于Pet,相当于一个弱指针。

#include <boost/pool/pool.hpp>	// requires boost::thread lib

template <class Entity, class... Args>		// use "parameter pack" to accept zero or more template arguments, aka., variadic template
class PoolManaged final: public Entity
{
public:
	PoolManaged(Args... args)
		: Entity(args...)
		, _guid(++GUID_SEED)
	{ /* empty */ }
	~PoolManaged() {_guid = 0;}
	int guid() const {return _guid;}

	// memory allocation and free is delegated to boost::pool
	static void * operator new(std::size_t size) throw(std::bad_alloc)
	{
		return mempool().malloc();
	}
	static void operator delete(void *mem, std::size_t size) throw()
	{
		return mempool().free(mem);
	}

private:
	int _guid;	// Globally Unique ID: to identify pool's objects
	static int GUID_SEED;
	static boost::pool<>& mempool()
	{
		static boost::pool<> sp(sizeof(PoolManaged<Entity, Args...>));
		return sp;
	}
};

template<class Entity, class... Args>
int PoolManaged<Entity, Args...>::GUID_SEED = 0;

// the user of above template
template<class PoolManaged>
class PoolPtr
{
public:
	PoolPtr(PoolManaged* ref)
		: _ref(ref), _refGuid(ref->guid())
	{ /* empty */ }

	// check if currently-refencing object is the old one
	bool isValid() const {return _refGuid == _ref->guid();}

	PoolManaged* operator ->() const
	{
		assert(_refGuid == _ref->guid());
		return _ref;
	}

private:
	PoolManaged*	_ref;
	int				_refGuid;
};

在使用时很简单,定义两个符号即可:

#include "poolmgr.h"

#include <iostream>

using namespace std;

class Player
{
public:
	Player(const string& name) : _name(name) { /* empty */ }
	const string& name() {return _name;}
private:
	string _name;
};

typedef PoolManaged<Player, string> PoolPlayer;			// use pool to manage Player objects
typedef PoolPtr<PoolPlayer>			PoolPlayerWeakPtr;	// use weak ptr to reference a pool's entity

class Pet
{
public:
	Pet(PoolPlayer* owner)
		: _player(owner)
	{ /* empty */ }

	void update()
	{
		if (_player.isValid())
		{
			cout << _player->name() << endl;
		}
		else
		{
			cout << "owner is lost.\n";
		}
	}
private:
	PoolPlayerWeakPtr _player;
};

int _tmain(int argc, _TCHAR* argv[])
{
	PoolPlayer* p = new PoolPlayer("Tom");
	Pet dog(p);
	dog.update();

	delete p;
	dog.update();

	PoolPlayer* p2 = new PoolPlayer("Jerry");
	dog.update();

	return 0;
}

PoolPlayer与PoolPlayerWeakPtr即可完成这项“野指针”的监督任务。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值