2012-03-08 10 views
6

Espero que esta pregunta sea apropiada para stackoverflow ... ¿Cuál es la diferencia entre almacenar bytes de datos sin procesar (8 bits) en un std::string en lugar de almacenarlos en std::vector<char> . Estoy leyendo datos binarios de un archivo y almacenando esos bytes sin procesar en un std::string. Esto funciona bien, no hay problemas o problemas para hacer esto. Mi programa funciona como se esperaba Sin embargo, otros programadores prefieren el enfoque std::vector<char> y sugieren que deje de usar std::string ya que no es seguro para los bytes sin formato. Entonces me pregunto por qué podría ser inseguro usar std::string para mantener los bytes de datos brutos? Sé que std::string se usa con mayor frecuencia para almacenar texto ASCII, pero un byte es un byte, por lo que no entiendo la preferencia del std::vector<char>.std :: string o std :: vector <char> para contener datos en bruto

¡Gracias por cualquier consejo!

+3

Solía ​​ser que no se garantizaba que std :: string proporcionara almacenamiento contiguo, lo que importa si se hacen cosas como '& s [0]' para obtener un puntero no const a los datos. Pero esto ya no es cierto a partir de C++ 11. –

+1

posible duplicado de [vector vs cadena para datos binarios] (http://stackoverflow.com/questions/1556229/vector-unsigned-char-vs-string-for-binary-data) –

Respuesta

12

El problema no es realmente si funciona o no. El problema es que es completamente confuso para el siguiente tipo que lee tu código. std::string es para mostrar texto. Cualquiera que lea tu código lo esperará. Declarará que su intento es mucho mejor con un std::vector<char>.

Aumenta su WTF/min en las revisiones de código.

+0

Nunca lo había pensado así. Buen punto. Pienso en std :: string como un contenedor que contiene bytes. Pueden ser bytes ASCII, pero no es obligatorio. En mi opinión, std :: string es std :: bytes, pero es bueno saber que los demás piensan de manera diferente. Puedo ver cómo esto sería confuso. – 01100110

+2

Para más puntos de vista, cuando pienso "byte", creo 'uint8_t'. En su mayor parte, solo uso 'char' cuando estoy realmente manteniendo datos de * character *, cuando estoy usando buffers (por ejemplo, usando' new char [] 'para asignar la memoria en la que voy a construir un objeto), o para jugar bien con alguna API establecida que usa 'char'. En general, preferiría tener un 'std :: vector ' para almacenar datos de bytes sin formato. – Hurkyl

+0

google use a std :: string para almacenar bytes sin formato en snappy. – GameDeveloper

5

En C++ 03, usando std::string para almacenar un conjunto de datos de bytes no era una buena idea. Según el estándar, std::string no tenía tiene para almacenar datos contiguamente. C++ 11 lo arregló para que sus datos tengan que ser contiguos.

Por lo tanto, no sería funcional hacerlo en C++ 03. No, a menos que haya investigado personalmente su implementación de la biblioteca estándar de C++ std::string para asegurarse de que sea contigua.

De cualquier manera, sugeriría vector<char>. Generalmente, cuando ve string, espera que sea una ... cadena. Ya sabes, una secuencia de caracteres en alguna forma de codificación. Un vector<char> hace que sea obvio que no es una cadena, sino una matriz de bytes.

+0

Gracias. Usamos C++ 11 para que los bytes sean contiguos. Mi idea de std :: string parece ser más amplia que la mayoría. Agradezco tu opinión Es bueno para mí entender por qué otros encuentran esto confuso, aunque funciona. – 01100110

3

Además del almacenamiento contiguo y problemas de claridad de código, me encontré con algunos errores bastante insidiosos tratando de usar std::string para contener bytes sin formato.

La mayoría de ellos se centran en tratar de convertir una matriz char de bytes a std::string cuando interactúan con bibliotecas C. Por ejemplo:

std::string password = "pass\0word"; 
std::cout << password.length() << std::endl; // prints 4, not 9 

Tal vez es posible solucionarlo mediante la especificación de la longitud:

std::string password("pass\0word", 0, 9); 
std::cout << password.length() << std::endl; // nope! still 4! 

Esto es probablemente porque el constructor espera recibir un C-secuencia, no una matriz de bytes. Podría haber una mejor manera, pero terminé con esto:

std::string password("pass0word", 0, 9); 
password[4] = '\0'; 
std::cout << password.length() << std::endl; // hurray! 9! 

Un poco torpe. Afortunadamente, encontré esto en pruebas unitarias, pero me hubiera perdido si mis vectores de prueba no tuvieran bytes nulos. Lo que hace que esto sea insidioso es que el segundo enfoque anterior funcionará bien hasta el conjunto contiene un byte nulo.

Hasta ahora std::vector<uint8_t> parece una buena opción (gracias J. N.y Hurkyl):

char p[] = "pass\0word"; 
std::vector<uint8_t> password(p, p, p+9); // :) 

Nota: no he probado el constructor iterador con std::string, pero este error es bastante fácil de hacer que podría valer la pena evitando incluso la posibilidad.

Lecciones aprendidas:

  • métodos de prueba de bytes de manejo witih vectores de prueba que contiene bytes nulos.
  • Tenga cuidado cuando (y yo diría que lo evito) usando std::string para contener bytes sin procesar.
+0

¿Se puede inicializar un vector de 'char' o' uint8_t' a partir de un literal de cadena en C++ 11? –

Cuestiones relacionadas