¿Por qué C++ 11 hizo que std:: string:: data() agregara un carácter de terminación nulo?




c++11 stdstring (2)

Anteriormente, eso era el trabajo de std::string::c_str() , pero a partir de C ++ 11, data() también lo proporciona, por qué se agregó el carácter de terminación nula de c_str() a std::string::data() ? A mí me parece una pérdida de ciclos de CPU, en los casos en que el carácter de terminación nula no es relevante en absoluto y solo se usa data() , un compilador C ++ 03 no tiene que preocuparse por el terminador, y no tiene que escribir 0 en el terminador cada vez que se cambia el tamaño de la cadena, pero un compilador de C ++ 11, debido a la garantía de data() , debe perder los ciclos de escritura 0 cada vez que se cambia el tamaño de la cadena, por lo que dado que potencialmente hace que el código sea más lento, supongo que tenían alguna razón para agregar esa garantía, ¿qué era?


Hay dos puntos para discutir aquí:

Espacio para el terminador nulo.

En teoría, una implementación de C ++ 03 podría haber evitado asignar espacio para el terminador y / o podría haber necesitado realizar copias (por ejemplo, no unsharing ).

Sin embargo, todas las implementaciones sanas asignaron espacio para el terminador nulo con el fin de admitir c_str() para comenzar, porque de lo contrario sería prácticamente inutilizable si no fuera una llamada trivial.

El propio terminador nulo.

Es cierto que algunas implementaciones very (1999), muy antiguas (2001) escribieron la \0 cada llamada c_str() .

Sin embargo, las implementaciones principales changed (2004) o ya eran así (2010) para evitar tal cosa antes de que se lanzara C ++ 11, de modo que cuando llegó el nuevo estándar, para muchos usuarios nada cambió.

Ahora, si una implementación de C ++ 03 debería haberlo hecho o no:

A mi me parece un desperdicio de ciclos de CPU.

Realmente no. Si llama a c_str() más de una vez, ya está perdiendo ciclos escribiéndolo varias veces. No solo eso, usted está jugando con la jerarquía de caché, lo que es importante tener en cuenta en los sistemas multiproceso. Recuerde que las CPUs multi-core / SMT comenzaron a aparecer entre 2001 y 2006 , lo que explica el cambio a implementaciones modernas que no son de CoW (incluso si existían sistemas con varias CPU un par de décadas antes).

La única situación en la que guardaría cualquier cosa es si nunca llamó a c_str() . Sin embargo, tenga en cuenta que cuando está redimensionando la cadena, de todos modos está reescribiendo todo. Un byte adicional será difícilmente medible.

En otras palabras, al no escribir el terminador en un nuevo tamaño, se está exponiendo a un peor rendimiento / latencia. Al escribirlo una vez, al mismo tiempo tiene que realizar una copia de la cadena, el comportamiento del rendimiento es mucho más predecible y evita las dificultades del rendimiento si termina utilizando c_str() , especialmente en sistemas de multiproceso.


La premisa de la pregunta es problemática.

una clase de cadena tiene que hacer muchas cosas expansivas, como asignar memoria dinámica, copiar bytes de un búfer a otro, liberar la memoria subyacente y así sucesivamente.

¿Qué te molesta es una mala instrucción de montaje? Créeme, esto no afecta su rendimiento, incluso en un 0,5%.

Al escribir un tiempo de ejecución de lenguaje de programación, no puede ser obsesivo con cada instrucción de ensamblaje pequeño. Usted tiene que elegir sus batallas de optimización sabiamente, y la optimización de una terminación nula no notable no es una de ellas.

En este caso específico, ser compatible con C es mucho más importante que la terminación nula.







c++03