¿"&s[0]" apunta a caracteres contiguos en una cadena std::?
Estoy haciendo algunos trabajos de mantenimiento y me encontré con 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 usar &s[0] sería seguro si fuera un std::vector, pero ¿es este un uso seguro de std::string?
No se garantiza que la asignación de una std::string sea contigua según el estándar C++ 98/03, pero C++ 11 obliga a que lo sea. En la práctica, ni Herb Sutter ni yo conocemos ninguna implementación que no utilice almacenamiento contiguo.
Tenga en cuenta que &s[0]
siempre se garantiza que la cosa funcione según el estándar C++ 11, incluso en el caso de cadena de longitud 0. No estaría garantizado si lo hiciera str.begin()
o &*str.begin()
, pero &s[0]
el estándar lo define operator[]
como:
Devuelve :
*(begin() + pos)
ifpos < size()
, en caso contrario una referencia a un objeto de tipoT
con valorcharT()
; el valor referenciado no será modificado
Continuando, data()
se define como:
Devuelve: Un puntero
p
tal quep + i == &operator[](i)
para cada unoi
en[0,size()]
.
(observe los corchetes en ambos extremos del rango)
Aviso : C++ 0x previo a la estandarización no garantizaba &s[0]
el funcionamiento con cadenas de longitud cero (en realidad, era un comportamiento explícitamente indefinido), y una revisión anterior de esta respuesta explicaba esto; Esto se solucionó en borradores estándar posteriores, por lo que la respuesta se actualizó en consecuencia.
Es seguro de usar. Creo que la mayoría de las respuestas fueron correctas una vez, pero el estándar cambió. Citando el estándar C++ 11, requisitos generales basic_string [string.require] , 21.4.1.5, dice:
Los objetos tipo char en un objeto basic_string se almacenarán de forma contigua. Es decir, para cualquier objeto basic_string s, la identidad &*(s.begin() + n) == &*s.begin() + n se mantendrá para todos los valores de n tales que 0 <= n < s.size ().
Un poco antes de eso, dice que todos los iteradores son iteradores de acceso aleatorio. Ambos bits respaldan el uso de su pregunta. (Además, Stroustrup aparentemente lo usa en su libro más reciente;))
No es improbable que este cambio se haya realizado en C++11. Creo recordar que se agregó la misma garantía para vector, que también obtuvo el puntero data() muy útil con esa versión.
Espero que ayude.
Técnicamente no, ya que std::string
no es necesario almacenar su contenido de forma contigua en la memoria.
Sin embargo, en casi todas las implementaciones (todas las implementaciones que conozco), los contenidos se almacenan de forma contigua y esto "funcionaría".