0

I've recently learned the pattern of the deserializing constructor (Deserializing constructor doesn't read data correctly) to use serialization with types that do not have default constructors. Now I'm trying to serialize an STL container of these objects, as in the example below:

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/split_member.hpp>
#include <boost/serialization/vector.hpp>

#include <fstream>

class Point
{
public:
    Point(double x) : mX(x) {}

    template<class TArchive>
    Point(TArchive& archive)
    {
        archive >> *this;
    }

    template<class TArchive>
    void serialize(TArchive& archive, const unsigned int version)
    {
        archive & mX;
    }

    double mX;
};

int main()
{
    std::vector<Point> pointVector;
    pointVector.push_back(Point(1));
    pointVector.push_back(Point(2));

    std::ofstream outputStream("test.txt");
    boost::archive::text_oarchive outputArchive(outputStream);

    outputArchive << pointVector;
    outputStream.close();

    std::vector<Point> readPointVector;
    std::ifstream inputStream("test.txt");
    boost::archive::text_iarchive inputArchive(inputStream);
    inputArchive >> readPointVector; // Compiler error - no matching function call to Point::Point()

    return 0;
}

It seems clear that this shouldn't work, but how would I tell the archive that it needs to use the deserializing constructor to construct the objects that it reads before adding them to the container?

---------- EDIT ----------

After implementing the suggestion in the only answer, this code compiles fine, but doesn't seem to deserialize correctly. The readPointVector only has size 1 but it should have size 2 (and the data is not correct in the one object that it does contain):

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

#include <fstream>

class Point
{
public:
    Point(double x) : mX(x) {}

    template<class TArchive>
    Point(TArchive& archive)
    {
        archive >> *this;
    }

    template<class TArchive>
    void serialize(TArchive& archive, const unsigned int version)
    {
        archive & mX;
    }

    double mX;
};

template <typename Archive>
Archive& operator >> (Archive& archive, std::vector<Point>& points)
{
    points.emplace_back(archive);
    return archive;
}

int main()
{
    std::vector<Point> pointVector;
    pointVector.push_back(Point(5.6));
    pointVector.push_back(Point(7.8));

    std::cout << pointVector.size() << std::endl; // outputs 2

    {
        std::ofstream outputStream("test.txt");
        boost::archive::text_oarchive outputArchive(outputStream);

        outputArchive << pointVector;
        outputStream.close();
    }

    std::vector<Point> readPointVector;
    std::ifstream inputStream("test.txt");
    boost::archive::text_iarchive inputArchive(inputStream);
    inputArchive >> readPointVector;

    std::cout << readPointVector.size() << std::endl; // outputs 1 (and readPointVector[0].mX is 2, but should be 7.8)

    return 0;
}
Community
  • 1
  • 1
David Doria
  • 9,873
  • 17
  • 85
  • 147
  • @JoachimPileborg So this is just impossible? What is one supposed to do in this case? – David Doria Mar 01 '16 at 20:13
  • Make sure that the type have a default constructor? – Some programmer dude Mar 01 '16 at 20:14
  • @JoachimPileborg, `std::vector` **never** worked this way, it doesn't require elements to be default constructable. There is only one call for constructor, it is either move or copy. – SergeyA Mar 01 '16 at 20:21
  • also see http://www.boost.org/doc/libs/1_45_0/libs/serialization/doc/serialization.html#constructors maybe ? – stijn Mar 01 '16 at 21:04
  • @stijn That is for pointer types. I've been told not to use that when not using pointers (first comment by SergeyA: http://stackoverflow.com/questions/35703958/disallow-serializing-an-object-directly-not-through-a-pointer-if-it-doesnt-ha) – David Doria Mar 01 '16 at 21:06

1 Answers1

2

You may specialize for vector of Points:

template <typename Archive>
Archive& operator >> (Archive& archive, std::vector<Point>& points)
{
    points.emplace_back(archive);
    return archive;
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302