Opened 14 years ago

Closed 14 years ago

#1942 closed Bugs (wontfix)

Pointers to elements in a std::map are not serilaized correctly

Reported by: bernhard.maeder@… Owned by: Robert Ramey
Milestone: To Be Determined Component: serialization
Version: Boost 1.35.0 Severity: Problem
Keywords: Cc:

Description

When serializing a std::map and some pointers that are referencing onto elements of that map, those pointers are not loaded correctly.

Here's the code:

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

struct dummy 
{
    template<typename Archive> 
    void serialize(Archive & ar, const unsigned int version)
    {        
    }  
};

struct map_ref_test
{
    std::map<std::size_t, dummy> m;    
    dummy * ref;

    template<typename Archive>
    void serialize(Archive & ar, const unsigned int version)
    {
        ar & m;
        ar & ref;
    }      
};

int main()
{
    std::ostringstream os;

    map_ref_test m;
    m.m[0] = dummy();
    m.m[1] = dummy();
    m.m[2] = dummy();
    m.ref = &(m.m[1]);

    // serialize
    boost::archive::text_oarchive out(os);        
    out << const_cast<map_ref_test const &>(m);

    // De-serialize
    map_ref_test m2; 
    std::string ser = os.str();
    std::istringstream is(ser);
    boost::archive::text_iarchive in(is);   

    in >> m2;

    std::cout << "0:   " << &m.m[0] << std::endl;
    std::cout << "1:   " << &m.m[1] << std::endl;
    std::cout << "2:   " << &m.m[2] << std::endl;
    std::cout << "ref: " << m.ref << std::endl << std::endl;

    std::cout << "0:   " << &m2.m[0] << std::endl;
    std::cout << "1:   " << &m2.m[1] << std::endl;
    std::cout << "2:   " << &m2.m[2] << std::endl;
    std::cout << "ref: " << m2.ref << std::endl;     
}

This creates the following output:

0:   0x805bfc4
1:   0x805bfe4
2:   0x805c004
ref: 0x805bfe4

0:   0x805ca04
1:   0x805ca24
2:   0x805ca44
ref: 0xbfacad5c

I'd expect the last line to read:

ref: 0x805ca24

The code works for std::vectors, so I'd assume it should work for maps also.

Change History (2)

in reply to:  description comment:1 by anonymous, 14 years ago

We have the same problem. When an instance of ClassB is serialized, all the saved pointers in map are lost.

We are using Boost 1.35.0 running on Fedora7(64 bits). gcc version 4.1.2

#include <string> #include <map>

#include <boost/serialization/serialization.hpp> #include <boost/serialization/access.hpp> #include <boost/serialization/is_abstract.hpp>

#include <boost/serialization/base_object.hpp> #include <boost/serialization/extended_type_info_typeid.hpp> #include <boost/serialization/export.hpp>

#include <boost/serialization/string.hpp>

#include <boost/mpl/and.hpp> #include <boost/serialization/map.hpp>

using namespace std; using namespace boost::serialization;

class A {

friend class boost::serialization::access; template<class Archive> void serialize(Archive & ar, const unsigned int version) { };

}

class B : public A { private:

friend class boost::serialization::access; template<class Archive> void serialize(Archive & ar, const unsigned int version) {

serialize base class information ar & boost::serialization::base_object<A>(*this); ar & value; ar & classACollection;

}

protected:

long value; std::map<long, ClassA * > classACollection;

public:

A(); virtual ~A();

} BOOST_CLASS_EXPORT(B);

class classA { private:

friend class boost::serialization::access; template<class Archive> void serialize(Archive & ar, const unsigned int version) {

ar & values;

}

protected:

std::map <long, ClassB *> values;

public:

ClassA(); ClassA(ClassA &object); virtual ~ClassA();

}

class B {

private:

friend class boost::serialization::access; template<class Archive> void serialize(Archive & ar, const unsigned int version) {

ar & value;

}

protected:

string value;

public:

ClassB(); ClassB(ClassB &object); virtual ~ClassB();

}

comment:2 by Robert Ramey, 14 years ago

Resolution: wontfix
Status: newclosed

After a lot of work, I managed to discover what the problem is.

The following case will fail when all three of the following are true:

a) object is untracked (map<>::value_type in your case

b) object contains something else that is tracked

c) The containing object is moved after being deserialized - load a map has to do.

In your case this can be address by adding:

namespace boost { \ namespace serialization { \ template<> \ struct tracking_level< std::map<std::size_t, dummy>::value_type > \ { \

typedef mpl::integral_c_tag tag; \ typedef mpl::int_< boost::serialization::track_always > type; \ BOOST_STATIC_CONSTANT( \

int, \ value = tracking_level::type::value \

); \

}; } }

I haven't found any general solution. I'll add a note to the documentation.

Robert Ramey

Note: See TracTickets for help on using tickets.