如何使用cereal将Texture对象序列化为ID并通过TextureManager反序列化?
使用cereal实现Texture指针的ID序列化与反序列化加载
完全可行,以下是具体实现步骤:
1. 调整Texture类的访问权限
首先需要让序列化逻辑能获取到Texture的唯一ID,最简单的方式是给Texture添加一个公共的ID获取方法:
class Texture { public: // 提供获取唯一ID的接口 const std::string& get_id() const { return id_; } private: std::string id_; // 保证唯一 };
如果不想暴露公共方法,也可以将cereal的序列化函数声明为Texture的友元。
2. 为std::shared_ptr编写自定义序列化逻辑
cereal允许为特定类型定制序列化/反序列化行为,我们需要针对std::shared_ptr<Texture>实现对应的保存和加载逻辑:
方式一:基于全局TextureManager(简单直接)
如果你的程序中有全局的TextureManager实例,可以用这种方式:
#include <cereal/cereal.hpp> #include <cereal/types/shared_ptr.hpp> #include <cereal/archives/json.hpp> // 声明全局TextureManager实例 extern TextureManager g_texture_manager; namespace cereal { // 序列化时:输出Texture的ID template <class Archive> void save(Archive& ar, const std::shared_ptr<Texture>& tex) { if (tex) { // 空命名参数让JSON直接输出ID字符串,符合期望格式 ar(cereal::make_nvp("", tex->get_id())); } else { ar(cereal::make_nvp("", std::string{})); // 空指针输出空字符串 } } // 反序列化时:通过ID从TextureManager加载Texture template <class Archive> void load(Archive& ar, std::shared_ptr<Texture>& tex) { std::string id; ar(cereal::make_nvp("", id)); if (!id.empty()) { tex = g_texture_manager.get_texture_by_id(id); } else { tex = nullptr; } } } // namespace cereal
方式二:基于cereal上下文传递(解耦更优)
如果不想依赖全局变量,可以通过cereal的上下文机制传递TextureManager指针,避免耦合:
namespace cereal { // 序列化逻辑和方式一一致 template <class Archive> void save(Archive& ar, const std::shared_ptr<Texture>& tex) { if (tex) { ar(cereal::make_nvp("", tex->get_id())); } else { ar(cereal::make_nvp("", std::string{})); } } // 反序列化时从上下文获取TextureManager template <class Archive> void load(Archive& ar, std::shared_ptr<Texture>& tex) { std::string id; ar(cereal::make_nvp("", id)); if (!id.empty()) { auto* texture_manager = ar.template getContext<TextureManager*>(); if (!texture_manager) { throw std::runtime_error("反序列化未设置TextureManager上下文"); } tex = texture_manager->get_texture_by_id(id); } else { tex = nullptr; } } } // namespace cereal
3. 声明Material的序列化接口
只需要给Material添加标准的cereal序列化模板即可:
struct Material { std::shared_ptr<Texture> texture1; std::shared_ptr<Texture> texture2; template <class Archive> void serialize(Archive& ar) { ar(CEREAL_NVP(texture1), CEREAL_NVP(texture2)); } };
4. 使用示例
序列化
Material mat; // 假设已为mat的texture1、texture2赋值 std::ofstream os("material.json"); cereal::JSONOutputArchive archive(os); archive(mat);
反序列化(方式二的情况)
Material loaded_mat; std::ifstream is("material.json"); cereal::JSONInputArchive archive(is); // 设置TextureManager上下文 archive.setContext(&my_texture_manager); archive(loaded_mat);
最终效果
序列化后的JSON格式完全符合你的预期:
{ "texture1": "/assets/dog.bmp", "texture2": "/assets/foo.jpg" }
注意事项
- 确保Texture的ID唯一且TextureManager能通过ID正确检索到对应资源
- 空指针会被序列化为空字符串,反序列化时转为
nullptr,可根据需求调整逻辑
内容的提问来源于stack exchange,提问作者Frederic Schönberger
相关产品推荐
相关产品推荐

