Serialize and Deserialize a C++ Object in Rcpp

Wush Wu — written Nov 7, 2015 — source

This post shows how to serialize a C++ object into a R raw vector object—the base type used by the internal R serialization—and how to deserialize it.

The following example shows a toy C++ class and the related serialize/deserialize functions. It shows how one can use the cereal header-only C++ library and Boost Iostreams in Rcpp. It relies on the corresponding Rcereal and BH packages which need to be installed. It also requires compilation with support for the C++11 standard, which we enable via the corresponding Rcpp plugin.

// Enable C++11 via this plugin 
// [[Rcpp::plugins("cpp11")]]

// [[Rcpp::depends(Rcereal)]]
// [[Rcpp::depends(BH)]]

#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/device/array.hpp>
#include <cereal/archives/binary.hpp>
#include <Rcpp.h>

struct MyClass {
    int x, y, z;

    // This method lets cereal know which data members to serialize
    template<class Archive>
    void serialize(Archive & archive) {
        archive( x, y, z ); // serialize things by passing them to the archive
    }
};

using namespace Rcpp;

//[[Rcpp::export]]
RawVector serialize_myclass(int x = 1, int y = 2, int z = 3) {
    MyClass my_instance;
    my_instance.x = x;
    my_instance.y = y;
    my_instance.z = z;
    RawVector retval(100);
    boost::iostreams::stream_buffer<boost::iostreams::array_sink> buf((char*) &retval[0], retval.size());
    std::ostream ss(&buf); {
        cereal::BinaryOutputArchive oarchive(ss);
        oarchive(my_instance);
    }
    return retval;
}

//[[Rcpp::export]]
void deserialize_myclass(RawVector src) {
    boost::iostreams::stream<boost::iostreams::array_source> ss((char*) &src[0], src.size());
    MyClass my_instance; {
        cereal::BinaryInputArchive iarchive(ss);
        iarchive(my_instance);
    }
    Rcout << my_instance.x << "," << my_instance.y << "," << my_instance.z << std::endl;
}

Thanks to how Rcpp and R interact, the compiler will automatically find the header file according to // [[Rcpp::depends(Rcereal)]] and // [[Rcpp::depends(BH)]]. The member function void serialize(Archive & archive) tells cereal how to serialize and deserialize the C++ class MyClass. Data will be saved and loaded if they are passed to the argument archive.

The cereal::BinaryOutputArchive oarchive(ss); defines an instance of bineary archive. The oarchive(my_instance); archives the instance of MyClass to the output stream and writes the data to the RawVector.

Similarly, cereal::BinaryInputArchive iarchive(ss); defines an instace of bineary archive. The iarchive(my_instance); reads the data from the RawVector and restores the content to the instance of MyClass.

Let’s try these two functions in R:

v <- serialize_myclass(1, 2, 4)
head(v)
[1] 01 00 00 00 02 00
deserialize_myclass(v)
1,2,4

As you can see, the instance of MyClass is successfully saved to v and loaded from v.

The API of cereal is similar to the one of Boost Serialization. The main difference is that the cereal prefers using () to send data to archives. Please visit the transition from Boost page for more details about the difference between cereal and Boost Serialization.

The most important advantage may be that cereal is header-only, which makes it easier to write portable package with cereal compared to Boost Serialization.

tags: serialization 

Related Articles