c++ - sinonimo - Ventajas de usar literal definido por el usuario para cadenas en lugar de literal de cadena
sentido literal y figurado (4)
-
Usar un literal de cadena C ++ significa que no necesitamos llamar a
strlen
para calcular la longitud. El compilador ya lo sabe. - Podría permitir implementaciones de biblioteca donde los datos de cadena apuntan a la memoria en el espacio global utilizando literales C siempre deben forzar una copia de los datos a la memoria de almacenamiento en la construcción.
El tema de las cadenas en la Documentación SO solía decir, en la sección Comentarios:
Desde C ++ 14, en lugar de usar
"foo"
, se recomienda usar"foo"s
, ya ques
es un literal de cadena, que convierte elconst char *
"foo"
enstd::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 una copia de elisión (creo), que sería más rápido que la llamada del constructor en el segundo caso.
Sin embargo, esto está (todavía no) garantizado, por lo que el primero también podría llamar a un constructor, el constructor de copia.
Ignorando los casos en los que se
requiere
usar
std::string
literales como
std::string str = "Hello "s + "World!"s;
¿Hay algún beneficio de usar
std::string
literales
std::string
lugar de los literales
const char[]
?
Además, UDL hace que sea más fácil 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
El consejo de usar
"blah"s
no tiene nada que ver con la eficiencia y todo con la corrección del código de principiante.
Los novatos de C ++ que no tienen experiencia en C, tienden a suponer que
"blah"
da como resultado 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 script.
Con
"blah" + 42
en C ++, sin embargo, uno solo incurre en Comportamiento indefinido, que se dirige más allá del final de la matriz de caracteres.
Pero si ese literal de cadena se escribe como
"blah"s
entonces uno obtiene un error de compilación, que es mucho más preferible.
Si eres parte de la multitud "Casi siempre automático", entonces el UDL es muy importante. Te permite hacer esto:
auto str = "Foo"s;
Y así,
str
será un
std::string
genuino, no un
const char*
.
Por lo tanto, le permite decidir cuándo hacer qué.
Esto también es importante para la deducción del tipo de devolución automática:
[]() {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 una copia de elisión (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 como no conoce la longitud, este constructor se ve obligado a usar
strlen
para obtenerlo (técnicamente,
char_traits<char>::length
, pero eso probablemente no será mucho más rápido).
Por el contrario:
std::string str = "foo"s;
Esto usará la plantilla UDL que tiene este prototipo:
string operator "" s(const char* str, size_t len);
Verá, el
compilador
conoce la longitud de un literal de cadena.
Entonces, el código UDL pasa un puntero a la cadena y un tamaño.
Y así, puede llamar al constructor
std::string
que toma un
const char*
y
un
size_t
.
Por lo tanto, no es necesario calcular la longitud de la cadena.
El consejo en cuestión no es que vayas y conviertas
cada
uso de un literal en la versión
s
.
Si está de acuerdo con las limitaciones de una serie de caracteres,
char
.
El consejo es que, si vas a almacenar ese literal en una
std::string
, es mejor hacerlo mientras todavía sea un literal y no un
const char*
.