what type str geeksforgeeks data array c++ c++11 language-lawyer stdstring

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) si pos < size() , de lo contrario, una referencia a un objeto de tipo T con valor charT() ; 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 que p + i == &operator[](i) para cada i 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 valor charT() , donde modificar el objeto a cualquier valor que no sea charT() conduce a un comportamiento indefinido.