Ventajas de usar literal definido por el usuario para cadenas en lugar de literal de cadena


El tema de cadenas en la Documentación SO solía decir, en la sección de Observaciones:

Desde C++14, en lugar de usar "foo", se recomienda usar "foo"s, ya que s es un literal de cadena, que convierte const char * "foo" to std::string "foo".

La única ventaja que veo usando

std::string str = "foo"s;

En lugar de

std::string str = "foo";

Es que en el primer caso el compilador puede realizar copy-elision (creo), que sería más rápido que la llamada del constructor en el segundo caso.

Sin embargo, esto (aún no) está garantizado, por lo que el primero también podría llamar a un constructor, el constructor de copia.

Ignorando casos donde es requerido para usar std::string literales como

std::string str = "Hello "s + "World!"s;

¿Hay algún beneficio de usar std::string literales en lugar de const char[] literales?

Author: Jonathan Leffler, 2016-07-28

4 answers

Si eres parte de la multitud "Casi Siempre Auto", entonces la UDL es muy importante. Te permite hacer esto:

auto str = "Foo"s;

Y así, str será un verdadero std::string, no un const char*. Por lo tanto, le permite decidir cuándo hacer qué.

Esto también es importante para la deducción de tipo de retorno automático:

[]() {return "Foo"s;}

O cualquier forma de deducción de tipo, realmente:

template<typename T>
void foo(T &&t) {...}

foo("Foo"s);

La única ventaja que veo usando [...] en lugar de [...] es que en el primer caso, el compilador puede realizar copy-elision (creo), que sería más rápido que la llamada del constructor en el segundo caso.

Copy-elision no es más rápido que la llamada del constructor. De cualquier manera, estás llamando a uno de los constructores del objeto. La pregunta es cuál :

std::string str = "foo";

Esto provocará una llamada al constructor de std::string que toma un const char*. Pero dado que std::string tiene que copiar la cadena en su propio almacenamiento, debe obtener la longitud de la cadena para hacerlo. Y ya que no sabe la length, este constructor se ve obligado a usar strlen para obtenerlo (técnicamente, char_traits<char>::length, pero eso probablemente no va a ser mucho más rápido).

Por el contrario:

std::string str = "foo"s;

Esto utilizará la plantilla UDL que tiene este prototipo:

string operator "" s(const char* str, size_t len);

Vea, el compilador conoce la longitud de un literal de cadena. Así que el código UDL se pasa un puntero a la cadena y un tamaño. Y por lo tanto, puede llamar al constructor std::string que toma un const char* y a size_t. Así que no hay necesidad de calculando la longitud de la cadena.

El consejo en cuestión no es que vayas por ahí y conviertas cada uso de un literal en la versión s. Si estás de acuerdo con las limitaciones de un array de chars, úsalo. El consejo es que, si vas a almacenar ese literal en un std::string, es mejor hacerlo mientras siga siendo un literal y no un nebuloso const char*.

 45
Author: Nicol Bolas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-28 20:27:11

El consejo de usar "blah"s no tiene nada que ver con la eficiencia y todo tiene que ver con la corrección para el código novato.

Los novatos de C++ que no tienen un fondo en C, tienden a asumir que "blah" resulta en un objeto de algún tipo de cadena razonable. Por ejemplo, para que uno pueda escribir cosas como "blah" + 42, que funciona en muchos lenguajes de escritura. Con "blah" + 42 en C++, sin embargo, uno solo incurre en un Comportamiento Indefinido, dirigiéndose más allá del final de la matriz de caracteres.

Pero si ese literal de cadena es escrito como "blah"s entonces uno obtiene un error de compilación, que es mucho preferible.

 17
Author: Cheers and hth. - Alf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-28 03:22:25

Además, UDL facilita tener \0 en la cadena

std::string s = "foo\0bar"s; // s contains a \0 in its middle.
std::string s2 = "foo\0bar"; // equivalent to "foo"s
 10
Author: Jarod42,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-09 09:09:37
  1. Usar un literal de cadena de C++ significa que no necesitamos llamar a strlen para calcular la longitud. El compilador ya lo sabe.
  2. Podría permitir implementaciones de bibliotecas donde los datos de cadena apuntan a la memoria en el espacio global, utilizando literales de C siempre se debe forzar una copia de los datos para amontonar la memoria en la construcción.
 2
Author: doron,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-28 03:13:19