c++ - ¿Debo comparar un std::string con “string” o “string” s?
c++14 c++17 (3)
Considere este fragmento de código:
bool foo(const std::string& s) {
return s == "hello"; // comparing against a const char* literal
}
bool bar(const std::string& s) {
return s == "hello"s; // comparing against a std::string literal
}
A
primera vista
, parece que comparar con un
const char*
necesita menos instrucciones de ensamblaje
1
, ya que el uso de un literal de cadena conducirá a una construcción in situ de la
std::string
.
Sin embargo, mirando la
referencia
del
operator==(const char*, const std::string&)
:
Todas las comparaciones se realizan a través de la función miembro
compare()
.
Según tengo entendido, esto significa que necesitaremos construir una
std::string
todos modos para realizar la comparación, por lo que sospecho que la sobrecarga será la misma al final (aunque esté oculta por la llamada al
operator==
).
(
EDITAR: Como se señaló en las respuestas, olvidé el hecho de que efectivamente se
s.compare(const char*)
en
foo()
, por lo que, por supuesto, no se realiza ninguna construcción en el lugar
)
- ¿Cuál de las comparaciones debería preferir?
- ¿Una versión tiene ventajas sobre la otra (puede estar en situaciones específicas)?
1 Soy consciente de que menos instrucciones de ensamblaje no significa necesariamente un código más rápido, pero no quiero entrar en el micro benchmarking aquí.
Según tengo entendido, esto significa que necesitaremos construir una
std::string
todos modos para realizar la comparación, por lo que sospecho que la sobrecarga será la misma al final (aunque esté oculta por la llamada aloperator==
).
Aquí es donde el razonamiento va mal.
std::compare
no necesita asignar su operando como una cadena terminada en nulo de estilo C para funcionar.
Según una de las sobrecargas:
int compare( const CharT* s ) const; // (4)
4) Compara esta cadena con la secuencia de caracteres terminada en nulo que comienza en el carácter señalado por
s
con longitudTraits::length(s)
.
Si bien asignar o no es un detalle de implementación, no parece razonable que una comparación de secuencia lo haga.
Ninguno.
Si quieres ser inteligente, compáralo con
"string"sv
, que devuelve un
std::string_view
.
Si bien la comparación con un literal como
"string"
no da lugar a una sobrecarga de asignación, se trata como una cadena terminada en nulo, con todas las desventajas concomitantes: no hay tolerancia para nulos incrustados, y los usuarios deben prestar atención al terminador nulo.
"string"s
hace una asignación, salvo
small-string-optimisation
o la
elision de asignación
.
Además, el operador pasa la longitud del literal, sin necesidad de contar, y permite nulos incrustados.
Y finalmente, el uso de
"string"sv
combina las ventajas de ambos enfoques, evitando sus desventajas individuales.
Además, un
std::string_view
es una bestia mucho más simple que un
std::string
, especialmente si este último usa SSO como lo hacen todos los modernos.
Al menos desde C ++ 14 (que generalmente permitía eludir asignaciones), los compiladores podrían en teoría optimizar todas las opciones a la última, dada la información suficiente (generalmente disponible para el ejemplo) y el esfuerzo, bajo la regla de "como si" . Aunque todavía no estamos allí.
No,
compare()
no requiere la construcción de un
std::string
para
const char*
operandos.
Estás usando la sobrecarga # 4 aquí .
La comparación con la cadena literal es la versión "gratuita" que estás buscando.
Instalar una
std::string
es completamente innecesaria.