Boost logo

Boost Users :

From: Martin Proulx (mproulx_at_[hidden])
Date: 2005-09-08 13:42:01


Robert Ramey wrote:
signature
OK I see the problem now.
 
Let me re-state it to be sure we're on the same page.
 
The class Person has a const member _name.  In C++ const members can only be set when an object is constructed.  In order to make sure no object is created without a name, There is no default constructor.  When the serialization library creates a new instance - that is when loading a pointer, the library uses the non-default constructor to initialize the const variable with the correct value.  When restoring the contents of an instance of the class Person that already exists the const member is not set.
 
Which seems totally correct to me.
 
I believe there's a fondamental concept that needs to be cleared up before going any further.

What does the unserialization of an instance means?  After some thought, I now realize it can mean at least two things:

1-) It's an operation akin to the assignment operator.  Unserializing means assigning new values to an already existing object.
2-) It means reconstructing the object as it originally was, in the manner a factory would.

It seems to me as if the serialization library does a mix of both.

The first approach is what operator>> does.  You declare something, call operator>> on it, and after that, the initial object has now been assigned the serialized value.

The library also does the second interpretation as it will reconstruct an instance if needed.  load_construct_data is the factory mechanism that recreates an actual instance.  This is used to restore objects that were saved through pointers or that were contained in STL containers.

The real question here is what is the intent in setting the member variable _name as const?  Standard C++ behavior for const members is that they
a) are only set when the instance is constructed.
b) cannot be changed thereafter.
 
Now if we do the following:
 
Person p("bob")
...
ar << p;
...
Person p1("anne");
...
ar >> p1;
 
What should p1 contain?  If you want p1 to contain "anne", then leave your program as it is.  If you want it to contain "bob" then:
 
a) remove the const from the member _name
b) implement the normal member serialization for _name.
c) at this point, loading pointers will result in _name being loaded twice. If this is a problem, you could
    i) add a default constructor and elminate the save/load construct data.  You might want to make the default constructor private and include friend boost::serialization::access to your class.  (I haven't tried this but I believe it should work.
 
An alternative to a) above would be to leave the "const" but use a const_cast inside the class serialization function.
 
At the heart of the matter here is the what we want const to mean.  Should const variables never change during the life of the class? - then we expect p1 to contain "bob".  Otherwise they are not really "const" in the traditional C++ sense and should be addressed by removing the const, or a cast or?
 
All the above discussion is really a discussion about what the assignment of an object that has a const member means.  Well, in C++, it really doesn't make sense and I agree.

That's why I believe there's some tiny piece missing from the serialization library.  We should also be able to unserialize instances through a factory that returns an actual object rather than having to use operator>>.

Here's some code showing this idea that works along with the previous example.

template<class T, class Archive>
void serialize_for_factory(Archive& oa, const T& object)
{
    boost::serialization::save_construct_data(oa, &object, 0); // Do something for the file version.
    oa << object;
}

template<class T, class Archive>
T unserialize_factory(Archive& ia)
{
    unsigned char memory[sizeof(T)];
   
    T* object = reinterpret_cast<T*>(memory);

    boost::serialization::load_construct_data(ia, object, 0); // Do something for the file version.

    T unserializedObject(*object); // Uses the copy constructor;
    object->~T();

    return unserializedObject;
}

void betterWay()
{
    Person John("John");
   
    stringstream stringStream;
    boost::archive::text_oarchive oa(stringStream);

    serialize_for_factory(oa, John);

    boost::archive::text_iarchive ia(stringStream);
    Person restoredPerson(unserialize_factory<Person>(ia));

    assert(restoredPerson.getName() == John.getName()); // Works
}


Do you believe something like this fits in the serialization library?

Thanks!

Martin

--
signature Tel: (450) 681-1681, #271

OKIOK

Enterprise and e-business security solutions
Solutions de sécurité d'entreprise et d'affaires électronique

Tel. : (450) 681.1681
http://www.okiok.com

This e-mail message (including attachments, if any) is intended for the use of the individual or entity to which it is addressed and may contain information that is privileged, proprietary, confidential and exempt from disclosure. If you are not the intended recipient, you are notified that any dissemination, distribution or copying of this communication is strictly prohibited. If you have received this communication in error, please notify the sender and erase this e-mail message immediately.
 
Le présent message électronique (y compris les pièces qui y sont annexées, le cas échéant) s'adresse au destinataire indiqué et peut contenir des renseignements de caractère privé ou confidentiel. Si vous n'êtes pas le destinataire de ce document, nous vous signalons qu'il est strictement interdit de le diffuser, de le distribuer ou de le reproduire. Si ce message vous a été transmis par erreur, veuillez en informer l'expéditeur et le supprimer immédiatement.


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net