[serialization] Handling of references into a std::map
Hello all I'm trying to serialize a std::map along with some pointers that are referencing onto some of the Value elements of that map. What I see now, is that those references are not loaded correctly. Here's what I do: #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::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 So, what am I doing wrong? Should this even work? BTW: I'm using Boost 1.33.1 Thanks a lot! Bernhard
Bernhard Maeder wrote:
I'm trying to serialize a std::map along with some pointers that are referencing onto some of the Value elements of that map. What I see now, is that those references are not loaded correctly.
You could save a reference to the map and the value of the key for the element. When you load the archive, you can use that information to reconstruct the reference to the element. --Johan Råde
Johan Råde <rade <at> maths.lth.se> writes:
Bernhard Maeder wrote:
You could save a reference to the map and the value of the key for the element. When you load the archive, you can use that information to reconstruct the
reference to the element.
--Johan Råde
Yes, I could do that, but it would be more complicated. In my real application, I don't keep the references to that map's values in the same place with the map; the reconstruction process would thus influence many other components as well, which I wouldn't want to do. If I understand Boost.Serialization correctly (and that is of course in doubt here! :-), it is able to accomplish these things for you and should thus make the serialization code much less verbose. Bernhard
This can't work. load a pointer creates a new pointer with a copy of the original object. adding the following to your test should make this clear ... std::cout << "ref: " << *m.ref << std::endl; ... std::cout << "ref: " << *m2.ref << std::endl; Robert Ramey Bernhard Maeder wrote:
Hello all
I'm trying to serialize a std::map along with some pointers that are referencing onto some of the Value elements of that map. What I see now, is that those references are not loaded correctly. Here's what I do:
#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::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
So, what am I doing wrong? Should this even work?
BTW: I'm using Boost 1.33.1
Thanks a lot! Bernhard
Robert Ramey <ramey <at> rrsd.com> writes:
This can't work.
load a pointer creates a new pointer with a copy of the original object.
adding the following to your test should make this clear
... std::cout << "ref: " << *m.ref << std::endl; ... std::cout << "ref: " << *m2.ref << std::endl;
Hmm, if I understand you correctly, then m2.ref should point to a copy of m.m[1] then, but not the same instance? The thing is, m2.ref isn't even that. Here's an enhanced example: I add a value variable to my dummy struct: struct dummy { int j; dummy() : j(-1) {} dummy(int i) : j(i) {} template<typename Archive> void serialize(Archive & ar, const unsigned int version) { ar & j; } }; And then print that value along with the addresses: ... std::cout << "0: " << &m.m[0] << " = " << m.m[0].j << std::endl; std::cout << "1: " << &m.m[1] << " = " << m.m[1].j << std::endl; std::cout << "2: " << &m.m[2] << " = " << m.m[2].j << std::endl; std::cout << "ref: " << m.ref << " = " << m.ref->j << std::endl; ... What I get is the following: 0: 0x8085c0c = 1 1: 0x8085c44 = 2 2: 0x8085c7c = 3 ref: 0x8085c44 = 2 0: 0x80864a4 = 1 1: 0x80864c4 = 2 2: 0x80864e4 = 3 ref: 0xbf81de0c = -1231556796 which indicates to me that it isn't a copy of the original element and that something unexpected is happening. As I understand Boost.Serialization's mechanics, one is allowed to store objects through pointers that are stored by-value elsewhere, as long as the by-value serialization is done before to the by-pointer one. I have some code where this (seemingly) works. For the above, e.g., replacing the map by a vector<dummy> makes everything work as expected: 0: 0x8082440 = 1 1: 0x8082444 = 2 2: 0x8082448 = 3 ref: 0x8082444 = 2 0: 0x8083368 = 1 1: 0x808336c = 2 2: 0x8083370 = 3 ref: 0x808336c = 2 Coincidince? Anyway, what would be the best way of doing this? Keeping pointers (instead of values) to dummy in the map should certainly fix the problem, right? Thanks! Bernhard
Robert Ramey wrote:
This can't work.
load a pointer creates a new pointer with a copy of the original object.
adding the following to your test should make this clear
... std::cout << "ref: " << *m.ref << std::endl; ... std::cout << "ref: " << *m2.ref << std::endl;
Ok, the author will know more than I! For the OP, you can have a map of pointers which will work. -- Sohail Somani http://uint32t.blogspot.com
Bernhard Maeder wrote:
Hello all
I'm trying to serialize a std::map along with some pointers that are referencing onto some of the Value elements of that map. What I see now, is that those references are not loaded correctly. Here's what I do:
This seems like a bug. If you change the map to an array or a std vector, it works as expected. -- Sohail Somani http://uint32t.blogspot.com
Sohail Somani <sohail <at> taggedtype.net> writes:
Bernhard Maeder wrote:
Hello all
I'm trying to serialize a std::map along with some pointers that are referencing onto some of the Value elements of that map. What I see now, is that those references are not loaded correctly. Here's what I do:
This seems like a bug. If you change the map to an array or a std vector, it works as expected.
Yes, I noticed that, too. Do you know if it's fixed in 1.34 or 1.35? Bernhard
Bernhard Maeder wrote:
Sohail Somani <sohail <at> taggedtype.net> writes:
Bernhard Maeder wrote:
Hello all
I'm trying to serialize a std::map along with some pointers that are referencing onto some of the Value elements of that map. What I see now, is that those references are not loaded correctly. Here's what I do:
This seems like a bug. If you change the map to an array or a std vector, it works as expected.
Yes, I noticed that, too. Do you know if it's fixed in 1.34 or 1.35?
I was testing against 1.35 so I assume not. I took a look at the code as well but I do not know why it didn't work as the code for the vector looks almost exactly the same as the code for a map. At the very least, take your example and file a ticket at http://svn.boost.org -- Sohail Somani http://uint32t.blogspot.com
participants (4)
-
Bernhard Maeder
-
Johan Råde
-
Robert Ramey
-
Sohail Somani