c++ - type - ¿Legal para sobrescribir el terminador nulo de std:: string?
string n c++ (4)
En C ++ 11, sabemos que se garantiza que std::string
sea contigua y terminada en nulo (o más charT()
, terminada por charT()
, que en el caso de char
es el carácter nulo 0).
Hay una API C que necesito usar que completa una cadena con un puntero. Escribe toda la cadena + terminador nulo. En C ++ 03, siempre me vi obligado a utilizar un vector<char>
, porque no podía suponer que la string
era contigua o terminada en nulo. Pero en C ++ 11 (asumiendo una clase basic_string
ajuste adecuadamente, que todavía es dudosa en algunas bibliotecas estándar), puedo.
¿O puedo? Cuando hago esto:
std::string str(length);
La cadena asignará length+1
byte, con el último rellenado por el terminador nulo. Eso es bueno. Pero cuando paso esto a la API C, va a escribir length+1
caracteres. Va a sobrescribir el terminador nulo.
Es cierto que va a sobrescribir el terminador nulo con un carácter nulo . Las probabilidades son buenas de que esto funcione (de hecho, no puedo imaginar cómo no podría funcionar).
Pero no me importa lo que "funciona". Quiero saber, de acuerdo con la especificación , si está bien sobreescribir el terminador nulo con un carácter nulo.
Lamentablemente, esto es UB, si interpreto la redacción correcta (en cualquier caso, no está permitido):
§21.4.5 [string.access] p2
Devuelve:
*(begin() + pos)
sipos < size()
, de lo contrario, una referencia a un objeto de tipoT
con valorcharT()
; el valor referenciado no se modificará .
(Error editorial que dice que T
no está charT
).
.data()
y .c_str()
apuntan básicamente al operator[]
( §21.4.7.1 [string.accessors] p1
):
Devuelve: Un puntero
p
tal quep + i == &operator[](i)
para cadai
en[0,size()]
.
Según la especificación, sobrescribir el NUL
terminación debe ser un comportamiento indefinido . Por lo tanto, lo correcto sería asignar length+1
caracteres en la cadena, pasar el búfer de cadena a la API C y luego resize()
a la length
:
// "+ 1" to make room for the terminating NUL for the C API
std::string str(length + 1);
// Call the C API passing &str[0] to safely write to the string buffer
...
// Resize back to length
str.resize(length);
(FWIW, probé el enfoque de "sobrescribir NUL" en MSVC10, y funciona bien).
Supongo que n3092 ya no está actualizado, pero eso es lo que tengo. La Sección 21.4.5 permite el acceso a un solo elemento. Requiere pos <= tamaño (). Si pos <size () entonces obtienes el elemento real, de lo contrario (es decir, si pos == size ()) entonces obtienes una referencia no modificable.
Creo que, en lo que respecta al lenguaje de programación, un tipo de acceso que podría modificar el valor se considera una modificación incluso si el nuevo valor es el mismo que el anterior.
¿Tiene g ++ una biblioteca pedante a la que puedes vincular?
LWG 2475 lo hizo válido al editar la especificación del operator[](size())
(texto insertado en negrita):
De lo contrario, devuelve una referencia a un objeto de tipo
charT
con el valorcharT()
, donde modificar el objeto a cualquier valor que no seacharT()
conduce a un comportamiento indefinido.