C++动态数据管理

代码

#pragma once
#include<string>
#include<unordered_map>
namespace MyStd
{
	class RuntimeDataManager
	{
	private:
		class RuntimeDataBase
		{
			friend class RuntimeDataManager;
		protected:
			virtual void ReleaseData() = 0;
			std::string id;
		public:
			RuntimeDataBase() {}
			RuntimeDataBase(const std::string& _id) :id(_id) {}
			RuntimeDataBase(const RuntimeDataBase& d) :id(d.id) {}
			std::string GetID()const
			{
				return id;
			}
		};
		std::unordered_map<std::string, RuntimeDataBase*>data;
	public:
		template<typename T>
		class RuntimeData :public RuntimeDataBase
		{
			friend class RuntimeDataManager;
		private:
			template<typename... Args>
			RuntimeData(const std::string& _id, Args&&... args) :RuntimeDataBase(_id), value(new T(std::forward<Args>(args)...)) {}
			template<typename... Args>
			RuntimeData() : value(nullptr) {}
			T* value;
		protected:
			virtual void ReleaseData()
			{
				delete value;
			}
		public:
			RuntimeData(const RuntimeData& data) :RuntimeDataBase(data), value(data.value) {}
			operator T*()const
			{
				return value;
			}
			T& operator* ()const
			{
				return *value;
			}
			T* operator-> ()const
			{
				return value;
			}
		};
		template<typename T>
		RuntimeData<T> GetData(const std::string& id)
		{
			if (auto iter = data.find(id); iter != data.end())
			{
				RuntimeData<T>* t = dynamic_cast<RuntimeData<T>*>(iter->second);
				if (t == nullptr)
					return RuntimeData<T>();
				return *t;
			}
			return RuntimeData<T>();
		}
		bool FindData(const std::string& id)
		{
			return data.find(id) != data.end();
		}
		template<typename T, typename...Args>
		RuntimeData<T> AddData(const std::string& id, Args&& ...args)
		{
			RemoveData(id);
			data.emplace(id, new RuntimeData<T>(id, std::forward<Args>(args)...));
			return GetData<T>(id);
		}
		bool RemoveData(const std::string& id)
		{
			if (auto iter = data.find(id); iter != data.end())
			{
				iter->second->ReleaseData();
				delete iter->second;
				data.erase(iter);
				return true;
			}
			return false;
		}
		template<typename T>
		bool RemoveData(const RuntimeData<T>& iter)
		{
			return data.erase(iter.id);
		}
		~RuntimeDataManager()
		{
			for (const auto& i : data)
			{
				i.second->ReleaseData();
				delete i.second;
			}
		}
	};
}

在RuntimeDataManager中,每一个数据都有唯一对应的id,类似于变量名,所有数据都存储在一个以id为key的map中,通过id可以对数据进行操作。RuntimeData类相当于该管理器的迭代器,是数据和其id的组合。设置RuntimeDataBase类则是为了使所有数据类型都有一个共同的基类,这样才能存在同一个容器中。

使用方法

注意:在同一个RuntimeDataManager中,id是唯一的,不能重复,同时也没有“访问权限”的概念,只要能访问manager对象,就能访问该对象中所有数据。但是,可以通过创建多个manager使数据更加有条理。

迭代器类型

迭代器即RuntimeDataManager::RuntimeData类。
对于迭代器类型,可以使用GetID()获取其id。此外,它重载了*,->运算符,可以当作指针使用,也可以隐式转换为指针。

添加数据

auto iter=manager.AddData<数据类型>(该数据的id,初始化列表);
  • 添加数据时,如果该id已经存在,会自动删除原数据。
  • “初始化列表”即该数据构造函数的参数,可以有多个。
  • 返回值为指向添加的数据的迭代器。

查找数据

auto iter = manager.GetData<数据类型>(该数据的id);
//或
bool b = manager.FindData(该数据的id);
  • 第一种方法返回指向该数据的迭代器。它但要求指定的id存在,还要求id对应的数据类型必须是用户指定的数据类型。如果没有找到该数据,或数据类型不匹配,迭代器对应的指针为nullptr。
  • 第二种方法只用于查询指定的id是否存在,对数据类型没有要求。

删除数据

bool b = manager.RemoveData(该数据的id);
  • 如果指定的id存在,删除并返回true;否则返回false。

实际应用

该类主要用于回调函数之间的数据传递。例如,开发一个服务端程序,当客户端请求“答题”时,服务端从题库中随机选一道题发送给客户端,接着客户端再传来答案,服务端要判断正误,就必须记录上一次选取的题目的答案。而一般来说选题与判断正误在不同的回调函数中,互相传递数据很不方便,并且在这个例子中数据需要动态创建、删除,所以用一个专门的类来管理非常必要。上面的例子用以下代码可以实现:

struct Question
{
	std::string mQuestion, mAnalytic;
	char mAnswer;
	Question(const std::string& question, char answer, const std::string& analytic)
		:mQuestion(question), mAnalytic(analytic), mAnswer(answer) {}
}; 
void onRequestQuestion(const std::string& clientid)
{
	Question* q = data.GetData<Question>(clientid + "_question");
	if (q == nullptr)
	{
	//从题库中选题
	...
	q = data.AddData<Question>(clientid + "_question",...);
	}
	SendMsg(clientid, q->mQuestion);
}
void onAnswerQuestion(const std::string& clientid,char answer)
{
	if (auto q = data.GetData<Question>(clientid + "_question"))
	{
		if (answer == q->mAnswer)
		{
			SendMsg(clientid, "恭喜,回答正确!");
		}
		else
		{
			SendMsg(clientid, "很遗憾,回答错误!");
		}
		data.RemoveData(q);
	}
	else
		SendMsg(clientid, "你还没有开始答题!");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值