Serializar una clase que contiene un std::string
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 int
los campos están bien, pero el std::string
campo 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 char
las 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.
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 serialize
funciona para serializar y deserializar los datos, dependiendo de cómo se llame. Consulte la documentación para obtener más información.
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).
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 ( string
lo 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 fstream
y leería los datos de él, así como una función inversa que tomaría un fstream
y 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
, ostream
serializar y restaurar su clase si desea ese azúcar sintáctico.