Re: [Boost-users] [Serialization] Problem serializingviabaseclassptr
Hello Robert,
Sorry for not giving you feedback earlier, I was on vacation. I've included your proposed changes in my test application but I still get the same compile error:
C:/Boost/include/boost-1_33_1/boost/archive/detail/oserializer.hpp: In function `void boost::archive::save(Archive&, T&) [with Archive = boost::archive::text_oarchive, T = const A*]':
C:/Boost/include/boost-1_33_1/boost/archive/basic_text_oarchive.hpp:78: instantiated from `void boost::archive::basic_text_oarchive<Archive>::save_override(T&, int) [with T = const A*, Archive = boost::archive::text_oarchive]'
C:/Boost/include/boost-1_33_1/boost/archive/detail/interface_oarchive.hpp:78: instantiated from `Archive& boost::archive::detail::interface_oarchive<Archive>::operator<<(T&) [with T = const A*, Archive = boost::archive::text_oarchive]'
../main.cpp:101: instantiated from here
C:/Boost/include/boost-1_33_1/boost/archive/detail/oserializer.hpp:567: error: incomplete type `boost::STATIC_ASSERTION_FAILURE<false>' does not have member `value'
make: *** [main.o] Error 1
Could you tell me what I'm missing?
Thanks again for your help,
Guy Letourneau
Test application:
#include <iostream>
#include <fstream>
#include
int main() { // Create a B object B* Child = new B;
// Set some data std::string Data = "test"; Child->SetValue( Data );
// Assign it to a A ptr // const A* Parent = Child; // ****** note new const - see rationale
// create and open a character archive for output std::ofstream ofs( "filename" );
// save data to archive { try { boost::archive::text_oarchive oa( ofs ); // write class instance to archive // *** big problem here. Dereferecing pointer to A yields a ref // *** to an A - regardless that ptr was a B. What you really want is: oa << Parent; // *** let serialization handle dererencing // *** instead of: //oa << *Parent; } catch( boost::archive::archive_exception& e ) { std::cout << "Save failed! : " << e.what(); std::cout.flush();
return false; } catch( ... ) { std::cerr << "Unknown Exception " << std::endl;
return false; }
// archive and stream closed when destructors are called }
delete Child; }
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
Guy Létourneau wrote:
Hello Robert,
Sorry for not giving you feedback earlier, I was on vacation. I've included your proposed changes in my test application but I still get the same compile error:
C:/Boost/include/boost-1_33_1/boost/archive/detail/oserializer.hpp: In function `void boost::archive::save(Archive&, T&) [with Archive = boost::archive::text_oarchive, T = const A*]': C:/Boost/include/boost-1_33_1/boost/archive/basic_text_oarchive.hpp:78: instantiated from `void boost::archive::basic_text_oarchive<Archive>::save_override(T&, int) [with T = const A*, Archive = boost::archive::text_oarchive]' C:/Boost/include/boost-1_33_1/boost/archive/detail/interface_oarchive.hpp:78: instantiated from `Archive& boost::archive::detail::interface_oarchive<Archive>::operator<<(T&) [with T = const A*, Archive = boost::archive::text_oarchive]' ../main.cpp:101: instantiated from here C:/Boost/include/boost-1_33_1/boost/archive/detail/oserializer.hpp:567: error: incomplete type `boost::STATIC_ASSERTION_FAILURE<false>' does not have member `value' make: *** [main.o] Error 1
Could you tell me what I'm missing?
Thanks again for your help,
Guy Letourneau
Test application:
#include <iostream> #include <fstream>
#include
#include #include class A { public:
A() { i = 1; };
virtual ~A() { };
virtual void Dummy() = 0;
private:
int i;
friend class boost::serialization::access;
template <class Archive> void serialize( Archive& ar, const unsigned int version ) { std::cout << "Serialization of A" << std::endl; std::cout.flush(); } }; BOOST_IS_ABSTRACT(A)
class B : public A { public:
B() { };
virtual ~B() { };
void Dummy() { };
void SetValue( std::string& value ) { Data = value; }
private:
friend class boost::serialization::access;
template <class Archive> void serialize( Archive& ar, const unsigned int version ) { ar & boost::serialization::base_object<A>( *this ); ar & Data; std::cout << "Serialization of B" << std::endl; std::cout.flush(); }
std::string Data; }; BOOST_CLASS_EXPORT(B)
int main() { // Create a B object B* Child = new B;
// Set some data std::string Data = "test"; Child->SetValue( Data );
// Assign it to a A ptr
**** // > const A* Parent = Child; // Parent is now const // nope- Parent is not const - it points to a const A - not the same thing !!! // try const A * const Parent = Child; // const pointer to a const A // also the following will work - I believe A * const Parent = Child;
// create and open a character archive for output std::ofstream ofs( "filename" );
// save data to archive { try { boost::archive::text_oarchive oa( ofs ); // write class instance to archive oa << Parent; // Ptr dereferencing is performed by the library } catch( boost::archive::archive_exception& e ) { std::cout << "Save failed! : " << e.what(); std::cout.flush();
return false; } catch( ... ) { std::cerr << "Unknown Exception " << std::endl;
return false; }
// archive and stream closed when destructors are called }
delete Child; }
-----Original Message----- From: boost-users-bounces@lists.boost.org [mailto:boost-users-bounces@lists.boost.org] On Behalf Of Robert Ramey Sent: Saturday, July 22, 2006 6:43 PM To: boost-users@lists.boost.org Subject: Re: [Boost-users] [Serialization] Problem serializingviabaseclassptr
Three show stopping problems in this code:
a) A doesn't have serialize method even though such a method is invoked by base object. see: http://www.boost.org/libs/serialization/doc/serialization.html
b) saving a non-const object - see rationale section
c) Main show stopper:
int main() { // Create a B object B* Child = new B;
// Set some data std::string Data = "test"; Child->SetValue( Data );
// Assign it to a A ptr // const A* Parent = Child; // ****** note new const - see rationale
// create and open a character archive for output std::ofstream ofs( "filename" );
// save data to archive { try { boost::archive::text_oarchive oa( ofs ); // write class instance to archive // *** big problem here. Dereferecing pointer to A yields a ref // *** to an A - regardless that ptr was a B. What you really want is: oa << Parent; // *** let serialization handle dererencing // *** instead of: //oa << *Parent; } catch( boost::archive::archive_exception& e ) { std::cout << "Save failed! : " << e.what(); std::cout.flush();
return false; } catch( ... ) { std::cerr << "Unknown Exception " << std::endl;
return false; }
// archive and stream closed when destructors are called }
delete Child; }
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
I'm running into what appears to be a bug in the serialization library, but maybe it is just a limitation on the
library's usage. I'm not getting any exceptions thrown during serialization/deserialization, but I'm getting corrupted
pointers after deserialiation.
I'm trying to serialize/deserialize an object that contains a vector of objects containing vectors (something like
below):
class TObject
{
int x;
}
class TObjectContainer
{
std::vector<TObject> ObjectVector;
};
class TRoot
{
std::vector<TObjectContainer> ObjectContainerVector;
std::vector
Ivan wrote:
I'm running into what appears to be a bug in the serialization library, but maybe it is just a limitation on the library's usage. I'm not getting any exceptions thrown during serialization/deserialization, but I'm getting corrupted pointers after deserialiation.
I'm trying to serialize/deserialize an object that contains a vector of objects containing vectors (something like below):
class TObject { int x; }
class TObjectContainer { std::vector<TObject> ObjectVector; };
class TRoot { std::vector<TObjectContainer> ObjectContainerVector; std::vector
ObjectPtrVector; }; In simple cases, serializing/deserializing a structure like the above "appears" to work, but I believe the deserialization code has a bug or two.
I think one bug is that the i index used to update the object_id_vectors in the reset_object_address is doubly incremented, which seems wrong at first glance (once in for-loop, then again at bottom of for-loop, basic_iarchive.cpp, lines 276 and 297).
This certainly looks like a bug to me - good call
The other bug appears to be in the way moveable_objects_recent and moveable_objects_end are being set prior to calling reset_object_address. My assumption is the intent here is to modify the addresses of "trackable" sub-objects contained within the vector element being moved, so that ptrs will be hooked back up correctly, but the moveable ptrs are being set up in such a way that the vector elements (TObject) of the sub-vector (ObjectVector) are getting their addresses modified when the stack version of TObjectContainer is copied to the vector.
This seems wrong, because the TObjects are allocated on the heap, so their addresses should not be updated in the object_vector_id table when the ObjectVector is copied. The end result is that I'm getting bad pointers to the TObjects after deserialization.
TObjects are de-serialized to the heap then added to the vector. Since the tracking saves the address TObject is serialized to, the address would be on the stack. reset_object_address sets the tracked address to the heap address after the item is appended to the vector. I thought I considered the case of a vector of vectors - but maybe not. I would expect that the objects get theire addresses fixed up twice- once when they are moved from the stack to the heap and once when the vector container itself is moved from the stack to the heap. Its possible that there is something missng . Robert Ramey
best regards,
Dan Notestein
Robert Ramey wrote:
Dan Notestein wrote:
The other bug appears to be in the way moveable_objects_recent and moveable_objects_end are being set prior to calling reset_object_address. My assumption is the intent here is to modify the addresses of "trackable" sub-objects contained within the vector element being moved, so that ptrs will be hooked back up correctly, but the moveable ptrs are being set up in such a way that the vector elements (TObject) of the sub-vector (ObjectVector) are getting their addresses modified when the stack version of TObjectContainer is copied to the vector.
This seems wrong, because the TObjects are allocated on the heap, so their addresses should not be updated in the object_vector_id table when the ObjectVector is copied. The end result is that I'm getting bad pointers to the TObjects after deserialization.
TObjects are de-serialized to the heap then added to the vector. Since the tracking saves the address TObject is serialized to, the address would be on the stack. reset_object_address sets the tracked address to the heap address after the item is appended to the vector.
I thought I considered the case of a vector of vectors - but maybe not. I would expect that the objects get theire addresses fixed up twice- once when they are moved from the stack to the heap and once when the vector container itself is moved from the stack to the heap. Its possible that there is something missng .
Yes, the TObjects are fixed up twice, but I think the second fixup is an error because vector<> doesn't really contain the data elements, it contains a ptr to the data elements. When the vector container is "copied" from the stack to the heap, the newly allocated internal vector element array will be randomly allocated from somewhere else in the heap, so using an offset based off the address of the new copy of the vector container won't work. I can think of two possible theoretical solutions to the problem: 1) Use the container::swap function to exchange internal data ptrs of the stack and heap copy of the vector. This gives the heap vector the ownership of the stack vector's elements. This seems the most efficient technique since it avoid reallocating and copy constructing the elements. There's also no need to fixup the ptrs to the elements using this technique. 2) Continue to use the copy constructor for the vector when transferring the vector from stack to heap, and use the internal array ptr inside the new copy of the vector to fixup the elements. This definitely seems like the lesser of the two options. I would have tried to make a fix for this, but the algorithm for handling the moveable ptrs that define the range of addresses to fixup was a little complicated for me to follow. In particular, I wasn't sure how to make the fixups take place so that truly "contained" data gets fixed up, while avoiding fixing up the data that is merely "pointed" to by data members (and hence shouldn't be fixed up when the container is copied). One idea I had was to keep around the size of the data objects being moved, so that the reset_address function could look for ptrs in the moveable_ptr range that have addresses between old_address and old_address+object_size. But I also figured there was a good chance that there is already information available somewhere on which items in the object_id table are "contained" vs "pointed to". best regards, Dan Notestein
participants (4)
-
Dan Notestein
-
Guy Létourneau
-
Ivan
-
Robert Ramey