Search code examples
c++serializationiocereal

Cereal seems to not properly serialize an std::string


I am trying to serialize a class into a binary, to that effect I first started trying to serialize an std::string member within the class, I wrote this serialization method:

template<typename Archive>
void ShaderProgram::serialize(Archive& archive, ShaderProgram& program)
{
    archive(CEREAL_NVP(program.program_name));
}

Then I am trying to serialize and immediately read the class:

ShaderProgram program;
std::filesystem::create_directories(fs::path(cached_shader_path).parent_path());
std::ofstream os(cached_shader_path, std::ios::binary);
cereal::BinaryOutputArchive archive_out( os );
ShaderProgram::serialize(archive_out, program);

std::ifstream is(cached_shader_path, std::ios::binary);
cereal::BinaryInputArchive archive_in( is );
ShaderProgram::serialize(archive_in, program);

Which results in:

terminate called after throwing an instance of 'cereal::Exception'
  what():  Failed to read 8 bytes from input stream! Read 0

The class I am testing this with is trivial:

struct ShaderProgram
{
    std::string program_name = "name";

    template<typename Archive>
        static void serialize(Archive& archive, ShaderProgram& program);
};
template<typename Archive>
void ShaderProgram::serialize(Archive& archive, ShaderProgram& program)
{
    archive(CEREAL_NVP(program.program_name));
}

I don;t understand why this fails.


Solution

  • Here is an example. All is fine with cereal. In plain C++ remove Rcpp connections.

    // [[Rcpp::depends(Rcereal)]]
    #include <string>
    #include <fstream>
    #include <cereal/archives/binary.hpp>
    #include <cereal/types/string.hpp>
    #include <cereal/access.hpp>
    #include <Rcpp.h>
    
    struct ShaderProgram
    {
      ShaderProgram(){};
      ShaderProgram(std::string program_name)
        : program_name{program_name}{};
      ~ShaderProgram() = default;
      
      std::string get_program_name() const {
        return program_name;
      }
      
    private:
      std::string program_name{};
      
      friend class cereal::access;
    
      template<class Archive>
      void serialize(Archive& archive)
      {
        archive(program_name);
      }
      
    };
    
    
    // [[Rcpp::export]]
    int main() {
      
      {
        ShaderProgram sp("King Kong 8");
        
        std::ofstream os("Backend/Serialize_StringProgram.bin", std::ios::binary);
        cereal::BinaryOutputArchive oarchive(os);
        oarchive(sp);
      }
      
      {
        ShaderProgram sp{};
        std::ifstream is("Backend/Serialize_StringProgram.bin", std::ios::binary);
        cereal::BinaryInputArchive iarchive(is);
        iarchive(sp);
        
        Rcpp::Rcout << sp.get_program_name() << std::endl;
      }
    
    }