You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 23:15:53