¿Cuándo debo usar string_view en una interfaz?

14

Estoy usando una biblioteca interna que fue diseñada para imitar una biblioteca de C ++ propuesta , y en algún momento en los últimos años veo que su interfaz ha cambiado de usar std::string a string_view .

Por lo tanto, debo cambiar mi código para ajustarme a la nueva interfaz. Desafortunadamente, lo que tengo que pasar es un parámetro std :: string, y algo que es un valor de retorno std :: string. Así que mi código cambió de algo como esto:

void one_time_setup(const std::string & p1, int p2) {
   api_class api;
   api.setup (p1, special_number_to_string(p2));
}

a

void one_time_setup(const std::string & p1, int p2) {
   api_class api;
   const std::string p2_storage(special_number_to_string(p2));
   api.setup (string_view(&p1[0], p1.size()), string_view(&p2_storage[0], p2_storage.size()));
}

Realmente no veo lo que este cambio me compró como el cliente API, aparte de más código (para posiblemente arruinarlo). La llamada a la API es menos segura (debido a que la API ya no posee el almacenamiento para sus parámetros), probablemente guardó el trabajo de mi programa 0 (debido a las optimizaciones de movimiento que los compiladores pueden hacer ahora), e incluso si guardara el trabajo, eso solo sería un par de asignaciones que no se realizarán y nunca se realizarán después del inicio o en un bucle grande en algún lugar. No para esta API.

Sin embargo, este enfoque parece seguir los consejos que veo en otras partes, por ejemplo esta respuesta :

  

Como nota aparte, desde C ++ 17, debes evitar pasar una const std :: string &   a favor de un std :: string_view:

Me parece sorprendente este consejo, ya que parece abogar por la sustitución universal de un objeto relativamente seguro por uno menos seguro (básicamente un puntero y una longitud glorificados), principalmente con fines de optimización.

Entonces, cuando debería ser usado string_view, y cuándo no?

    
pregunta T.E.D. 16.01.2018 - 21:21

3 respuestas

14
  1. ¿La funcionalidad que toma el valor debe tomar posesión de la cadena? Si es así, use std::string (non-const, non-ref). Esta opción le da la opción de moverse explícitamente en un valor también si sabe que nunca más se usará en el contexto de la llamada.
  2. ¿La funcionalidad acaba de leer la cadena? Si es así, use std::string_view (const, non-ref) esto se debe a que string_view puede manejar std::string y char* fácilmente sin problemas y sin hacer una copia. Esto debería reemplazar todos los parámetros const std::string& .

En última instancia, no deberías nunca llamar al constructor std::string_view como eres. std::string tiene un operador de conversión que administra la conversión automáticamente.

    
respondido por el Mgetz 16.01.2018 - 21:45
11

Un std::string_view trae algunos de los beneficios de un const char* a C ++: a diferencia de std::string , una string_view

  • no posee memoria,
  • no asigna memoria,
  • puede apuntar a una cadena existente en algún desplazamiento, y
  • tiene un nivel menos de direccionamiento de puntero que un std::string& .

Esto significa que una string_view a menudo puede evitar copias, sin tener que lidiar con punteros en bruto.

En el código moderno, std::string_view debería reemplazar casi todos los usos de los parámetros de función const std::string& . Este debe ser un cambio compatible con la fuente, ya que std::string declara que un operador de conversión es std::string_view .

El hecho de que una vista de cadena no ayude a en su caso de uso específico , ya que debe crear una cadena de todos modos, no significa que sea una mala idea en general. La biblioteca estándar de C ++ tiende a estar optimizada por generalidad más que por conveniencia. El argumento "menos seguro" no se cumple, ya que no debería ser necesario para crear la vista de cadena usted mismo.

    
respondido por el amon 16.01.2018 - 21:48
6
  

Me parece sorprendente este consejo, ya que parece abogar por la sustitución universal de un objeto relativamente seguro por uno menos seguro (básicamente un puntero y una longitud glorificados), principalmente con fines de optimización.

Creo que esto es un poco mal entendido el propósito de esto. Si bien es una "optimización", realmente deberías pensar en que no te atajas de tener que usar un std::string .

Los usuarios de C ++ han creado docenas de diferentes clases de cadenas. Clases de cadena de longitud fija, clases optimizadas de SSO con el tamaño del búfer como un parámetro de plantilla, clases de cadena que almacenan un valor de hash utilizado para compararlas, etc. Algunas personas incluso usan cadenas basadas en COW. Si hay algo que a los programadores de C ++ les encanta hacer, es escribir clases de cadena.

Y eso ignora las cadenas creadas y que pertenecen a las bibliotecas de C. char* s desnudo, tal vez con un tamaño de algún tipo.

Entonces, si está escribiendo alguna biblioteca y toma un const std::string& , el usuario ahora tiene que tomar cualquier cadena que esté usando y copiarla a un std::string . Tal vez docenas de veces.

Si desea acceder a la interfaz específica de cadena de std::string , ¿por qué debería copiar la cadena? Eso es un desperdicio.

Los principales motivos para no tomar un string_view como parámetro son:

  1. Si su objetivo final es pasar la cadena a una interfaz que tome una cadena terminada en NUL ( fopen , etc.). Se garantiza que std::string está terminado en NUL; string_view no lo es. Y es muy fácil subscribir una vista para que no esté terminada en NUL; la subcadena a std::string copiará la subcadena en un rango terminado en NUL.

    Escribí un tipo de estilo string_view terminado por NUL para exactamente este escenario. Puede realizar la mayoría de las operaciones, pero no las que rompen su estado terminado en NUL (recorte desde el final, por ejemplo).

  2. Problemas de por vida. Si realmente necesita copiar ese std::string o, de lo contrario, la matriz de caracteres sobreviva a la función de llamada, es mejor declararlo por adelantado tomando un const std::string & . O simplemente un std::string como un parámetro de valor. De esa manera, si ya tienen una cadena de este tipo, puede reclamar la propiedad de la misma de inmediato, y la persona que llama puede pasar a la cadena si no necesitan mantener una copia de la misma.

respondido por el Nicol Bolas 17.01.2018 - 07:33

Lea otras preguntas en las etiquetas