2016-04-25 8 views
1

TLDR: Ich möchte eine Klassenserialisierung von der Implementierungsebene object_class_info zu object_serializable übergehen, Kompatibilität mit alten Datendateien behalten, während immer Dateien im neuen Format schreiben.Boost-Serialisierung: Übergang von versionierter Klasse zu object_serializable

Begründung: Als ich begann, die Boost Serialization-Bibliothek zu verwenden, erkannte ich nicht, dass es bereits mit einer Kopfzeile (complex.hpp) zur Serialisierung std::complex<double> kam. Stattdessen schrieb ich meine eigene, freistehende Serialisierungsfunktion:

namespace boost { namespace serialization { 
    template<class Archive, typename T> 
    void serialize(Archive& ar, std::complex<T>& comp, const unsigned int version) { 
    ar & reinterpret_cast<T(&)[2]>(comp)[0]; 
    ar & reinterpret_cast<T(&)[2]>(comp)[1]; 
    } 
} 

Diese standardmäßig ermöglicht Version und Klassen Info-Tracking, den Code nach unten ziemlich viel verlangsamt. Die Serialisierungsfunktion, die mit Boost geliefert wird, ist ein bisschen schneller.

Ich würde jetzt gerne auf die Verwendung der Boost-Version immer beim Schreiben neuer Datendateien, aber immer noch in der Lage sein, alte Dateien einzulesen. Das Einlesen neuer Dateien mit einer alten Binärdatei ist kein Problem.

Das Problem ist, dass die neue Serialisierung (natürlich) nicht versioniert ist. Außerdem sehe ich nicht einmal, wie ich versuchen könnte, ein Archiv mit der alten Version des Codes zu lesen und sofort wieder mit der neuen Version zu schreiben, da die Deserialisierungs-/Serialisierungseigenschaften globale Eigenschaften sind.

Was wäre der beste Weg, entweder a) alte und neue Dateien transparent einzulesen, während immer neue Dateien geschrieben werden, oder b) eine alte Datei einzulesen und sofort in das neue Format zu schreiben?

+0

„mit einem alten binären in neuen Dateien zu lesen, ist kein Thema“ einstellen - was bedeutet, dass bedeuten – sehe

+0

@sehe: Ich möchte alte Datendateien mit neuen Binärdateien aus dem neuen Code kompiliert lesen. Ich möchte neue Datendateien mit vorhandenen Binärdateien aus früheren Versionen des Codes nicht einlesen. – Claudius

Antwort

1

Sie können die alte Implementierung beibehalten und verwenden, wenn die Dateiversion "alt" ist.

Verwenden Sie die Boost-Version der komplexen Serialisierung nur beim Speichern oder wenn die Dateiversion "neu" ist.

Dies sollte trivial sein, wenn Sie ein Objekt haben, serialisiert werden die komplexen Daten enthalten, weil die Version auf dem enthaltenden Objekt stoßen kann dieses

UPDATE

Probe zu erreichen, einen einfachen Wrapper zu rufen Sie den alten Stil der Serialisierung:

Live On Coliru

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

template <typename T> struct old_format_wrapper { 
    T& wrapped; 
    old_format_wrapper(T& w) : wrapped(w) {} 
}; 

template <typename T> 
old_format_wrapper<T> old_format(T& w) { return {w}; } 

namespace boost { namespace serialization { 
    template<class Archive, typename T> 
     void serialize(Archive& ar, old_format_wrapper<std::complex<T> >& comp, unsigned) { 
      ar & reinterpret_cast<T(&)[2]>(comp.wrapped)[0]; 
      ar & reinterpret_cast<T(&)[2]>(comp.wrapped)[1]; 
     } 
} } 

struct IHaveComplexData { 
    std::complex<double> data; 

    template <typename Ar> void serialize(Ar& ar, unsigned version) { 
     switch(version) { 
      case 0: { // old 
        auto wrap = old_format(data); 
        ar & wrap; 
       } 
       break; 
      case 1: // new 
      default: 
       ar & data; // uses boost serialization 
       break; 
     } 
    } 
}; 

int main() { 
    { 
     boost::archive::text_oarchive oa(std::cout); 
     IHaveComplexData o { { 2, 33 } }; 
     oa << o; 
    } 

    { 
     std::istringstream iss("22 serialization::archive 13 0 0 0 0 2.00000000000000000e+00 3.30000000000000000e+01"); 
     boost::archive::text_iarchive ia(iss); 
     IHaveComplexData o; 
     ia >> o; 
     std::cout << o.data; 
    } 
} 

Drucke (je nach Boost-Version):

22 serialization::archive 13 0 0 0 0 2.00000000000000000e+00 3.30000000000000000e+01 
(2,33) 

Natürlich können Sie jetzt BOOST_CLASS_VERSION(IHaveComplexData, 1)

+0

Ich bin nicht sicher, dass dies funktionieren wird, da es viele Objekte gibt, die diesen Typ enthalten, und die Boost-Wrapper um 'serialize' eine Versionsnummer erwarten. Das heißt, wie sage ich Boost, manchmal einen versionierten Typ zu erwarten und manchmal nicht (von derselben Klasse!)? – Claudius

+0

Serialisierungsformat ist sowieso eine Eigenschaft Ihrer Typen. Kannst du mir ein Beispiel zeigen, was schwierig/langwierig/unmöglich wäre? – sehe

+0

Die Boost-Serialisierungsbibliothek behandelt den größten Teil des unordentlichen Bits, d. H. Klassenversionierung, Klassennamen usw. Sie ruft dann einfach die Funktion 'serialize()' für die Klasse auf, die ich serialisieren möchte. Das Problem ist, dass diese Klassenversionierung/anderer Overhead, d. H. Zusätzliche Informationen, die die Boost-Bibliothek erwartet, von einem Typmerkmal der serialisierten Klasse bestimmt wird. Meine Frage ist im Wesentlichen, wie ich das nur in Teilen des Programms ein-/ausschalten kann (die Ladebits). – Claudius