2009-01-13 11 views
44

En general, ¿cuál es la mejor manera de almacenar datos binarios en C++? Las opciones, hasta donde puedo decir, se reducen a usar cadenas o vector <char> s. (Voy a omitir la posibilidad de char * s y malloc() s ya que me refiero específicamente a C++).Forma "adecuada" para almacenar datos binarios con C++/STL

Normalmente solo uso una cadena, sin embargo, no estoy seguro de si hay gastos generales que me faltan, o conversiones que STL hace internamente que podrían interferir con la cordura de los datos binarios. ¿Alguien tiene alguna indicación (har) sobre esto? ¿Sugerencias o preferencias de una forma u otra?

Respuesta

38

vector de char es bueno porque la memoria es contigua. Por lo tanto, puede usarlo con muchas API de C, como los conectores de berkley o las API de archivos. Puede hacer lo siguiente, por ejemplo:

std::vector<char> vect; 
    ... 
    send(sock, &vect[0], vect.size()); 

y funcionará correctamente.

Puede tratarlo esencialmente como cualquier otro búfer de caracteres dinámicamente asignado. Puede escanear hacia arriba y hacia abajo buscando números mágicos o patrones. Puedes analizarlo parcialmente en su lugar. Para recibir desde un socket, puede cambiar el tamaño muy fácilmente para agregar más datos.

La desventaja es el cambio de tamaño no es terriblemente eficiente (cambiar el tamaño o preasignar con prudencia) y la eliminación de la parte frontal de la matriz también será muy ineficaz. Si necesita, por ejemplo, extraer solo uno o dos caracteres a la vez de la estructura de datos con mucha frecuencia, copiar en una copia antes de este procesamiento puede ser una opción. Esto le cuesta una copia y la memoria deque no es contigua, por lo que no puede simplemente pasar un puntero a una API de C.

En pocas palabras, aprenda sobre las estructuras de datos y sus intercambios antes de sumergirse, sin embargo, el vector de carbonilla es típicamente lo que veo que se usa en la práctica general.

+2

buena respuesta. para la parte de aprendizaje: encontré una buena imagen que muestra el uso de contenedores hace algún tiempo, y la incrustó en esta respuesta: http://stackoverflow.com/questions/366432/extending-stdlist#366710 –

6

Yo uso std::string para esto también, y nunca he tenido un problema con él.

un "puntero", que acabo de recibir un claro recordatorio de una pieza de código ayer: al crear una cadena de un bloque de datos binarios, utilice el formulario std::string(startIter, endIter) constructor, no la forma std::string(ptr, offset, length) - que hace este último la suposición de que el puntero apunta a una cadena estilo C e ignora cualquier cosa después del primer carácter cero (copia "hasta" el length especificado, no length caracteres).

+0

Hmmm. De acuerdo con http://www.cplusplus.com/reference/string/string/string.html, std :: string (char * ptr, offset, length) ctor debe copiar * todos los bytes * de longitud, incluso incluyendo cero bytes. Es el std :: string (string const &, offset, length) ctor que copia * hasta * bytes de longitud. –

+0

Esto me llevó a buscarlo nuevamente, y parece que there * is * no std :: string (char * ptr, offset, length) constructor. El constructor que toma desplazamiento y longitud requiere std :: string como primer parámetro, por lo que construía automáticamente una cadena a partir de los bytes, que es lo que la truncó. –

+0

Tienes razón. Lo siento, quise decir que std :: string (char * ptr, size_t length) ctor debe copiar todos los bytes. –

3

Sin duda, debe utilizar un contenedor de carbón, pero el contenedor que desea utilizar depende de su aplicación.

Los caracteres tienen varias propiedades que los hacen útiles para almacenar datos binarios: el estándar no permite ningún "relleno" para un tipo de datos char, lo cual es importante ya que significa que no obtendrá basura en el diseño binario. También se garantiza que cada carácter es exactamente de un byte, lo que lo convierte en el único tipo de datos simple antiguo (POD) con ancho establecido (todos los demás se especifican en términos de límites superiores y/o inferiores).

El debate sobre el contenedor stl apropiado con el que almacenar los caracteres se maneja bien por Doug arriba. Cuál necesita depende completamente de su caso de uso. Si solo está sosteniendo un bloque de datos que itera, sin ninguna consulta especial, agregar/eliminar o empalmar necesidades, preferiría vector, lo que hace que sus intenciones sean más claras que std :: string, que muchas bibliotecas y funciones asumirán tiene una cadena estilo c terminada en nulo.

8

El mayor problema con std :: string es que el estándar actual no garantiza que su almacenamiento subyacente sea contiguo.Sin embargo, no hay implementaciones conocidas de STL donde la cadena no es contigua, por lo que en la práctica probablemente no fallará. De hecho, el nuevo estándar C++ 0x va a solucionar este problema, al exigir que std :: string use un buffer contiguo, como std :: vector.

Otro argumento en contra de la cadena es que su nombre sugiere que contiene una cadena de caracteres, no un búfer binario, lo que puede causar confusión a quienes leen el código.

Dicho esto, recomiendo vector también.

Cuestiones relacionadas