How to serialize a map of pointers in boost library?

Viewed 84

I would like to serialize a map of pointers.

Map creation:

float *data = new float[1000];
std::map<int, std::map<std::string, float*> > mapa;
mapa[4]["foo"] = data;

Serialize map to file:

std::ofstream ofs("somefile");
boost::archive::binary_oarchive oa(ofs);
oa<<mapa;
ofs.close();

Loading map from file:

std::ifstream ifs("somefile", std::ios::binary);
boost::archive::binary_iarchive ia(ifs);
std::map<int, std::map<std::string, float*> > newMapa;
ia >> newMapa;
ifs.close();

How can I do it properly?

Example with compilation errors: https://godbolt.org/z/76fMbxMhf

1 Answers

The strong typedef has been designed to wrap primitives into trackable types: https://www.boost.org/doc/libs/1_78_0/libs/serialization/doc/strong_typedef.html

BOOST_STRONG_TYPEDEF(float, Float)

However this will introduce considerable (!) overhead, because every single element needs tracking. In your example, it would make 1000x more sense to replace the pointer with the array index.

While you're at it, replace it with std::vector<float> so you don't have lifetime issues (and leaks).

Finally, make sure the archive is complete before you close the file or even read from it again.

Take #1

Live On Coliru

#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/serialization/map.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/string.hpp>

#include <fstream>
#include <iostream>
#include <numeric>
#include <sstream>

using ConvolutedIndex = std::map<int, std::map<std::string, size_t>>;

int main()
{   
    auto data = std::vector<float>(1000);
    std::iota(data.begin(), data.end(), 0.0); // fill with sample data

    float* element = &data[rand() % data.size()]; // pick random element

    std::cout << "Random pick: " << *element << " at " << element << "\n";

    {
        std::ofstream                   ofs("filename", std::ios::binary);
        boost::archive::binary_oarchive oa(ofs);
        oa << ConvolutedIndex{
            {4,
             {
                 {"foo", element - data.data()},
             }},
        };
    } // also closes file, but more importantly, completes archive first

    {
        std::ifstream                   ifs("filename", std::ios::binary);
        boost::archive::binary_iarchive ia(ifs);

        ConvolutedIndex newMapa;
        ia >> newMapa;

        std::cout<< "The element recovered: " << data.at(newMapa.at(4).at("foo")) << "\n";
    }
}

Prints e.g.

Random pick: 383 at 0x1f142dc
The element recovered: 383

Take #2

That still has problems, because you never serialized the floats being indexed. Easily remedied:

Live On Coliru

#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/serialization/map.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/vector.hpp>

#include <fstream>
#include <iostream>
#include <numeric>
#include <sstream>

using Data            = std::vector<float>;
using ConvolutedIndex = std::map<int, std::map<std::string, size_t>>;

int main()
{   
    {
        Data data(1000);
        std::iota(data.begin(), data.end(), 0.0); // fill with sample data

        float* element = &data[rand() % data.size()]; // pick random element
        std::cout << "Random pick: " << *element << " at " << element << "\n";

        std::ofstream                   ofs("filename", std::ios::binary);
        boost::archive::binary_oarchive oa(ofs);

        oa << data << ConvolutedIndex{
            {4,
             {
                 {"foo", element - data.data()},
             }},
        };
    } // also closes file, but more importantly, completes archive first

    {
        std::ifstream                   ifs("filename", std::ios::binary);
        boost::archive::binary_iarchive ia(ifs);

        Data            newData;
        ConvolutedIndex newMapa;
        ia >> newData >> newMapa;

        std::cout<< "The element recovered: " << newMapa.at(4).at("foo") << "\n";
    }
}

Now everybody's happy (well, except the Gods of <random>, but something needs to be the exercise for the reader):

Random pick: 383 at 0x1bd930c
The element recovered: 383
Related