Robin Thuran Malhotra
Robin Thuran Malhotra

Reputation: 594

Boost serialize string *

I'm trying to create a serialize function within my class, called location, and send it after serializing. I can't figure out why I'm getting an error, but maybe it's because I'm trying to serialize a string*.

Here's a minimal example

#include <iostream>
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/serialization.hpp>

struct WithPointers {
    WithPointers(const char* of = nullptr, const char* n = nullptr) {
        if (n) name = new std::string(n);
    }

    WithPointers(WithPointers const&) = delete;
    WithPointers& operator=(WithPointers const&) = delete;

    ~WithPointers() { 
        delete name; 
    }

    std::string* name = nullptr;

    template <class Archive>
    void serialize(Archive &ar, unsigned int) {
        ar & name;
    }
};

struct WithoutPointers {

    WithoutPointers(const char* of = nullptr, const char* n = nullptr) {
        if (n) name = n;
    }

    std::string name;

    template <class Archive>
    void serialize(Archive &ar, unsigned int) {
        ar & name;
    }
};

#include <iostream>
#include <sstream>

int main()
{
    std::string serialized; 

    typedef WithoutPointers Location; // DOESN'T COMPILE
    //typedef WithPointers Location;  // COMPILES

    {
        Location l1("da location", "da name");
        std::ostringstream oss;
        boost::archive::text_oarchive oa(oss);

        oa << l1;
        serialized = oss.str();
    }

    std::cout << "serialized: '" << serialized << "'\n";
}    

It works if we use WithoutPointers

Upvotes: 2

Views: 3643

Answers (1)

sehe
sehe

Reputation: 392833

To be fair, I don't see a reason why this wouldn't work. It appears to me to be a kind of aribitrary limitation, potentially even a bug.

To contrast, here's a version that simply wraps the std::string:

struct XString {
    std::string s;

    template <class Archive>
    void serialize(Archive &ar, unsigned int) {
        ar & s;
    }
};

Interestingly, using this everything works as expected:

struct WithPointers {
    WithPointers(const char* n = nullptr) {
        if (n) name = new XString ({ n });
    }

    WithPointers(WithPointers const&) = delete;
    WithPointers& operator=(WithPointers const&) = delete;

    ~WithPointers() { 
        delete name; 
    }

    XString* name = nullptr;

    template <class Archive>
    void serialize(Archive &ar, unsigned int) {
        ar & name;
    }
};

See it Live On Coliru

Prints:

serialized: '22 serialization::archive 11 0 0 1 1 0
0 7 da name'
Deserialized as 'da name'

Summary

I'd still advise against using the raw std::string*. Other than that you should probably mention this problem on the Boost mailing lists

Full Listing

For reference:

#include <iostream>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/serialization.hpp>

struct XString {
    std::string s;

    template <class Archive>
    void serialize(Archive &ar, unsigned int) {
        ar & s;
    }
};

struct WithPointers {
    WithPointers(const char* n = nullptr) {
        if (n) name = new XString ({ n });
    }

    WithPointers(WithPointers const&) = delete;
    WithPointers& operator=(WithPointers const&) = delete;

    ~WithPointers() { 
        delete name; 
    }

    XString* name = nullptr;

    template <class Archive>
    void serialize(Archive &ar, unsigned int) {
        ar & name;
    }
};

#include <iostream>
#include <sstream>

int main()
{
    std::string serialized; 

    typedef WithPointers Location;

    {
        Location l1("da name");
        std::ostringstream oss;
        boost::archive::text_oarchive oa(oss);

        oa << l1;
        serialized = oss.str();
    }

    std::cout << "serialized: '" << serialized << "'\n";

    {
        Location l2;
        std::istringstream iss(serialized);
        boost::archive::text_iarchive ia(iss);

        ia >> l2;
        std::cout << "Deserialized as '" << l2.name->s << "'\n";
    }
}

Upvotes: 1

Related Questions