c++ c++14 c++17 string-comparison string-literals

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 al operator== ).

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 longitud Traits::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.