2012-07-05 26 views
5

Estoy tratando de serializar binariamente los datos del vector. En este ejemplo a continuación, serializo una cadena y luego deserializo de nuevo a un vector, pero no obtengo la misma información con la que comencé. ¿Por qué es este el caso?serialización de vectores

vector<size_t> v; 
v.push_back(1); 
v.push_back(2); 
v.push_back(3); 

string s((char*)(&v[0]), 3 * sizeof(size_t)); 

vector<size_t> w(3); 
strncpy((char*)(&w[0]), s.c_str(), 3 * sizeof(size_t)); 

for (size_t i = 0; i < w.size(); ++i) { 
    cout << w[i] << endl; 
} 

que esperar para obtener la salida

1 
2 
3 

pero en lugar de obtener la salida

1 
0 
0 

(en gcc-4.5.1)

+0

@Mark: No creo que sea el caso. –

Respuesta

4

El error está en la llamada a strncpy. Desde la página enlazada:

Si la longitud de src es menor que n, strncpy() rellena el resto de dest con bytes nulos.

Así, después del primer byte en el 0 datos serializados se encuentra el resto de la matriz de datos w 's se rellena con 0 s.

Para solucionar esto, utilizar un bucle for, o std::copy

std::copy(&s[0], 
      &s[0] + v.size() * sizeof(size_t), 
      reinterpret_cast<char *>(w.data())); 

OMI, en lugar de utilizar std::string como un tampón, sólo tiene que utilizar una matriz char para contener los datos serializados.

Example en Ideone

+0

Buena captura en el 'strncpy', nunca supe de esa" característica "y estaba desconcertado de por qué su código no funcionó. –

+0

Gracias por la explicación. ¿Por qué std :: copy es mejor que memcpy? – typedef

+0

Dado que está copiando una matriz de enteros, ambos funcionarán igual. Pero digamos que el vector contenía un objeto que administraba algún recurso. memcpy realizaría una copia bit a bit del objeto, que probablemente no sea la forma en que lo quiere copiar. std :: copy, por otro lado, invocará al operador de asignación asegurando que el objeto se copia correctamente. – Praetorian

2

strncpy es una pila gigante de fallar. Terminará pronto en su entrada porque el size_t tiene algunos bytes cero, que interpreta como el terminador NULO, dejándolos como construidos por defecto 0. Si ejecutó esta prueba en una máquina BE, todos serían 0. Use std::copy.

-1

Para serializar este vector en una cadena, Primero quiere convertir cada uno de los elementos de este vector de un int en una cadena que contiene la misma representación ascii de ese número, esta operación puede ser llamada serialización de un int Encadenar.

Así, por ejemplo, suponiendo un entero es de 10 dígitos que podemos

// create temporary string to hold each element 
char intAsString[10 + 1]; 

continuación, convertir el número entero a una cadena

sprintf(intAsString, "%d", v[0]); 

o

itoa(v[0], intAsString, 10 /*decimal number*/); 

También puede hacer uso de ostringstream y < < operador

si observa los contenidos de la memoria de intAsString yv [0], son muy diferentes, el primero contiene las letras ascii que representan el valor de v [0] en el sistema decimal (base 10) mientras v [0] contiene la representación binaria del número (porque así es como las computadoras almacenan números).

+1

Me parece claro que quiere una serialización binaria, no una serialización de texto. Además, 'sprintf' y' itoa' en código C++? –

+0

y creó una cadena para contener el resultado, por eso supuse que quería la serialización de texto. Gracias por el comentario :) –

+0

No, la cadena se copia a un vector, y el vector contiene el resultado. La cadena es simplemente un búfer binario. –

-1

La forma más segura sería simplemente recorrer el vector y almacenar los valores individualmente en una matriz de caracteres de tamaño 3 * sizeof (size_t). De esta forma, no tiene una dependencia en la estructura interna de la implementación de la clase vector.

+0

Tanto el vector como la cadena están garantizados para ser contiguos y sin relleno en C++ 11, por lo que no es un problema. –