Serializar una clase que contiene un std::string

Resuelto iwasinnamuknow asked hace 13 años • 6 respuestas

No soy un experto en C++ pero he serializado cosas un par de veces en el pasado. Desafortunadamente, esta vez estoy intentando serializar una clase que contiene un std::string, lo cual entiendo que es muy parecido a serializar un puntero.

Puedo escribir la clase en un archivo y volver a leerla. Todos intlos campos están bien, pero el std::stringcampo muestra un error de "dirección fuera de límites", presumiblemente porque apunta a datos que ya no están allí.

¿Existe una solución estándar para esto? No quiero volver a charlas matrices, pero al menos sé que funcionan en esta situación. Puedo proporcionar el código si es necesario, pero espero haber explicado bien mi problema.

Estoy serializando enviando la clase a a char*y escribiéndola en un archivo con std::fstream. La lectura, por supuesto, es todo lo contrario.

iwasinnamuknow avatar Aug 13 '11 03:08 iwasinnamuknow
Aceptado

Simplemente escribir el contenido binario de un objeto en un archivo no sólo no es portátil sino que, como habrás reconocido, no funciona con datos de puntero. Básicamente tiene dos opciones: o escribe una biblioteca de serialización real, que maneja std::strings correctamente, por ejemplo, usando c_str() para enviar la cadena real al archivo, o usa la excelente biblioteca de serialización boost . Si es posible, recomendaría lo último; luego puedes serializar con un código simple como este:

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

class A {
    private:
        std::string s;
    public:
        template<class Archive>
        void serialize(Archive& ar, const unsigned int version)
        {
            ar & s;
        }
};

Aquí, la función serializefunciona para serializar y deserializar los datos, dependiendo de cómo se llame. Consulte la documentación para obtener más información.

Antti avatar Aug 12 '2011 21:08 Antti

El método de serialización más sencillo para cadenas u otros blobs con tamaño variable es serializar primero el tamaño a medida que serializa números enteros y luego simplemente copiar el contenido en el flujo de salida.

Al leer, primero lee el tamaño, luego asigna la cadena y luego la completa leyendo el número correcto de bytes de la secuencia.

Una alternativa es utilizar un delimitador y un sistema de escape, pero requiere más código y es más lento tanto en la serialización como en la deserialización (sin embargo, el resultado puede mantenerse legible para los humanos).

6502 avatar Aug 12 '2011 21:08 6502

Tendrá que utilizar un método de serialización más complicado que convertir una clase en a char*y escribirla en un archivo si su clase contiene datos exógenos ( stringlo hace). Y tiene razón acerca de por qué aparece un error de segmentación.

Crearía una función miembro que tomaría un fstreamy leería los datos de él, así como una función inversa que tomaría un fstreamy escribiría su contenido para restaurarlo más tarde, así:

class MyClass {
pubic:
    MyClass() : str() { }

    void serialize(ostream& out) {
        out << str;
    }

    void restore(istream& in) {
        in >> str;
    }

    string& data() const { return str; }

private:
    string str;
};

MyClass c;
c.serialize(output);

// later
c.restore(input);

También puede definir operator<<, operator>>trabajar con istream, ostreamserializar y restaurar su clase si desea ese azúcar sintáctico.

Seth Carnegie avatar Aug 12 '2011 21:08 Seth Carnegie