posicionamiento para name metadatos mejorar keywords etiquetas etiqueta codigo buscadores c++ storage language-lawyer string-literals

c++ - name - ¿Se garantiza que el almacenamiento para los mismos literales de cadena de contenido sea el mismo?



posicionamiento web etiquetas (4)

El Estándar no garantiza que las direcciones de literales de cadena con el mismo contenido sean las mismas. De hecho, [lex.string]/16 dice:

Si todos los literales de cadena son distintos (es decir, se almacenan en objetos que no se superponen) y si las evaluaciones sucesivas de un literal de cadena producen el mismo objeto u otro diferente no se especifica.

¡La segunda parte incluso dice que es posible que no obtengas la misma dirección cuando una función que contiene una cadena literal se llama por segunda vez! Aunque nunca he visto a un compilador hacer eso.

Por lo tanto, utilizar el mismo objeto de matriz de caracteres cuando se repite un literal de cadena es una optimización de compilador opcional. Con mi instalación de g ++ y las marcas de compilación predeterminadas, también encuentro que obtengo la misma dirección para dos literales de cadena idénticos en la misma unidad de traducción. Pero como ha adivinado, obtengo diferentes si el mismo contenido literal de cadena aparece en diferentes unidades de traducción.

Un punto interesante relacionado: también se permite que diferentes literales de cadena utilicen matrices superpuestas. Es decir, dado

const char* abcdef = "abcdef"; const char* def = "def"; const char* def0gh = "def/0gh";

es posible que encuentre que abcdef+3 , def y def0gh son todos el mismo puntero.

Además, esta regla sobre la reutilización o la superposición de objetos literales de cadena solo se aplica al objeto de matriz sin nombre directamente asociado con el literal, que se utiliza si el literal decae inmediatamente en un puntero o está vinculado a una referencia a la matriz. También se puede usar un literal para inicializar una matriz nombrada, como en

const char a1[] = "XYZ"; const char a2[] = "XYZ"; const char a3[] = "Z";

Aquí, los objetos de la matriz a1 , a2 y a3 se inicializan con el literal, pero se consideran distintos del almacenamiento literal real (si ese almacenamiento existe, incluso) y siguen las reglas de los objetos normales, por lo que el almacenamiento para esas matrices no se superpondrá.

¿Es seguro el siguiente código? Podría ser tentador escribir código similar a esto:

#include <map> const std::map<const char*, int> m = { {"text1", 1}, {"text2", 2} }; int main () { volatile const auto a = m.at("text1"); return 0; }

El mapa está diseñado para ser usado solo con cadenas literales.

Creo que es perfectamente legal y parece estar funcionando, sin embargo, nunca vi una garantía de que el indicador del literal utilizado en dos lugares diferentes sea el mismo. No pude lograr que el compilador genere dos punteros separados para literales con el mismo contenido, así que comencé a preguntarme qué tan firme es la suposición.

Solo me interesa si los literales con el mismo contenido pueden tener diferentes punteros. O más formalmente, ¿puede el código de arriba excepto?

Sé que hay una forma de escribir código para estar seguro de que funciona, y creo que el enfoque anterior es peligroso porque el compilador podría decidir asignar dos almacenamientos diferentes para el literal, especialmente si se colocan en diferentes unidades de traducción. Estoy en lo cierto


El estándar de C ++ no requiere una implementación para desduplicar los literales de cadena.

Cuando un literal de cadena reside en otra unidad de traducción u otra biblioteca compartida que requeriría que el vinculador ( ld ) o el vinculador de tiempo de ejecución ( ld.so ) hagan la desduplicación literal de la cadena. Que no lo hacen.


No, el estándar C ++ no ofrece tales garantías.

Dicho esto, si el código está en la misma unidad de traducción, sería difícil encontrar un ejemplo de contador. Si main() está en una traducción diferente, un ejemplo de contador podría ser más fácil de producir.

Si el mapa está en una biblioteca enlazada dinámica diferente o en un objeto compartido, es casi seguro que no es el caso.

El calificador volatile es una pista falsa.


Si dos literales de cadena con el mismo contenido exacto son exactamente el mismo objeto, no se especifica, y en mi opinión es mejor no confiar en él. Para citar el estándar:

[lex.string]

16 evaluación de un resultado de cadena literal en un objeto de cadena literal con duración de almacenamiento estático, se inicializa a partir de los caracteres dados como se especifica anteriormente. Si todos los literales de cadena son distintos (es decir, se almacenan en objetos que no se superponen) y si las evaluaciones sucesivas de un literal de cadena producen el mismo objeto u otro diferente no se especifica.

Si desea evitar la sobrecarga de std::string , puede escribir un tipo de vista simple (o usar std::string_view en C ++ 17) que es un tipo de referencia sobre un literal de cadena. Úselo para hacer comparaciones inteligentes en lugar de confiar en la identidad literal.