Pregunta

Estoy haciendo algunos trabajos de mantenimiento y corrió a través de algo como lo siguiente:

std::string s;
s.resize( strLength );  
// strLength is a size_t with the length of a C string in it. 

memcpy( &s[0], str, strLength );

Sé que utilizando & s [0] sería seguro si era un std :: vector, pero este es un uso seguro de std :: string?

¿Fue útil?

Solución

A std :: asignación de cadena no se garantiza que sea contigua bajo el estándar de C ++ 98/03, pero C ++ 11 fuerzas que lo sea. En la práctica, ni yo ni herb Sutter sabe de una aplicación que no utiliza almacenamiento contiguo.

Tenga en cuenta que la cosa &s[0] siempre se garantiza que funcione por el C ++ 11 estándar, incluso en el caso de cadena 0 de longitud. No estaría garantizado si lo hizo str.begin() o &*str.begin(), pero para los &s[0] norma define operator[] como:

  

Devuelve : *(begin() + pos) si pos < size(), de lo contrario una referencia a un objeto de tipo T con valor charT(); el valor de referencia no será modificado

Continuando, data() se define como:

  

Las devoluciones:. Un puntero p que tales p + i == &operator[](i) para cada i en [0,size()]

(aviso los corchetes en ambos extremos de la gama)


Aviso : previa a la normalización C ++ 0x no garantizaba &s[0] para trabajar con cadenas de longitud cero (en realidad, era un comportamiento no definido de forma explícita), y una versión anterior de esta respuesta ha explicado esto; esto se ha solucionado en los borradores tarde estándar, por lo que la respuesta ha sido actualizado en consecuencia.

Otros consejos

Técnicamente, no, ya que no se requiere std::string para almacenar su contenido de forma contigua en la memoria.

Sin embargo, en casi todas las implementaciones (cada implementación de la que soy consciente), el contenido se almacena de forma contigua y esto haría "trabajo".

Es seguro de usar. Creo que la mayoría de las respuestas eran correctas una vez, pero el estándar cambiado. Citando de C ++ 11 estándar, basic_string requisitos generales [string.require] , 21.4.1.5, dice:

  

El char-como objetos en un objeto basic_string se almacenará de forma contigua. Es decir, para cualquier basic_string   objeto s, la identidad & * (s.begin () + n) == & * s.begin () + n se mantenga durante todos los valores de n tal que 0   <= N

Un poco antes de eso, se dice que todos los iteradores son iteradores de acceso aleatorio. Ambos bits apoyan el uso de su pregunta. (Además, BS parecer lo utiliza en su más reciente libro;))

No es poco probable que este cambio se hace en C ++ 11. Me parece recordar que la misma garantía se añadió a continuación para el vector, que también tiene muy útiles los de datos () puntero con esa versión.

Espero que ayude.

Los lectores deben notar que esta pregunta se hizo en 2009, cuando el C ++ 03 estándar fue la publicación actual. Esta respuesta se basa en que la versión de la Norma, en el que std::strings son no garantizada para utilizar almacenamiento contiguo. Dado que esta pregunta no se hizo en el contexto de una plataforma en particular (como gcc), hago suposiciones sobre la plataforma de OP - en particular, el tiempo o no se utiliza el almacenamiento contigious para la string

.

Información legal? Tal vez tal vez no. ¿Seguro? Probablemente, pero tal vez no. Buen código? Bueno, no vamos a ir allí ...

¿Por qué no hacer:

std::string s = str;

... o:

std::string s(str);

... o:

std::string s;
std::copy( &str[0], &str[strLen], std::back_inserter(s));

... o:

std::string s;
s.assign( str, strLen );

El código podría funcionar, pero más por suerte que por juicio, se hace suposiciones acerca de la aplicación que no están garantizados. Sugiero que determinan la validez del código es irrelevante si bien es un sentido más complicación que se reduce fácilmente a simplemente:

std::string s( str ) ;

o si asignar a un objeto std :: string existente, simplemente:

s = str ;

y luego dejar que std :: string en sí determinar cómo lograr el resultado. Si se va a recurrir a este tipo de tonterías, entonces es posible que así no va a utilizar std :: string y se adhieren a la reintroducción ya que están todos los peligros asociados con las cadenas C.

Esto es generalmente no seguro, independientemente de si la secuencia de la cadena interna se almacena en la memoria de manera continua o no. No podría haber muchos otros detalles de implementación relacionados con la forma en que la secuencia controlada es almacenada por objeto std::string, además de la continuidad.

Un verdadero problema práctico con el que podría ser el siguiente. No se requiere la secuencia controlada de std::string para ser almacenados como una cadena de cero terminados. Sin embargo, en la práctica, muchos (? La mayoría) de las implementaciones optan por sobredimensionar el buffer interno para el 1 y almacenar la secuencia como una cadena terminada en cero de todos modos ya que simplifica la implementación del método c_str(): acaba de devolver un puntero al buffer interno y que está hecho.

El código que ha citado en su pregunta no hace ningún esfuerzo para poner fin a cero los datos se copian en la memoria intermedia interna. Es muy posible que simplemente no sabe si cero de terminación es necesaria para esta aplicación de std::string. Es muy posible que se basa en el búfer interno se llena de ceros después de la llamada a resize, por lo que el carácter adicional asignado para el cero de terminación por la aplicación está convenientemente pre-establecido en cero. Todo esto es un detalle de implementación, lo que significa que esta técnica depende de algunos supuestos bastante frágiles.

En otras palabras, en algunas implementaciones, lo que probablemente tiene que usar strcpy, no memcpy para obligar a los datos en la secuencia controlada por el estilo. Mientras que en algunas otras implementaciones que tendría que utilizar memcpy y no strcpy.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top