2012-04-05 29 views
12

"Siempre se debe usar std::string sobre cadenas de estilo c (char *)" es un consejo que aparece para casi todos los códigos fuente publicados aquí. Si bien el consejo es sin duda bueno, las preguntas que se abordan no permiten elaborar sobre el ¿por qué? aspecto del consejo en detalle. Esta pregunta es para servir como un marcador de posición para el mismo.¿Por qué debería uno usar std :: cadena sobre cadenas estilo c en C++?

Una buena respuesta debe abarcar los siguientes aspectos (en detalle):

  1. Por qué debe uno usar std::string sobre cadenas estilo C en C++?
  2. ¿Cuáles son las desventajas (si las hay) de la práctica mencionada en #1?
  3. ¿Cuáles son los escenarios en que lo contrario de los consejos mencionados en #1 es una buena práctica?
+0

Planeo etiquetar esto [C++ - Faq] (http://stackoverflow.com/questions/tagged/c%2b%2b-faq) y discutiré lo mismo en [C++ Lounge] (http: // chat .stackoverflow.com/rooms/10/loungec) en breve. –

+2

¡¿Esto todavía se está preguntando en 2012 ?! Además, ¿cuándo está el consejo de usar 'std :: string' alguna vez ** no ** acompañado de racionalización? –

+1

@KarlKnechtel: Lo siento, parece que soy un novato en C++ a diferencia de ti :) Sin embargo, me molestaría en leer toda la pregunta y entender el propósito detrás de ella en lugar de solo leer el título antes de comentar. –

Respuesta

13
  1. std :: string gestiona su propia memoria, lo que puede copiar, crear, destruir fácilmente.
  2. No puede usar su propio buffer como std :: string.
  3. Debe pasar una cadena c/búfer a algo que espera tomar posesión del búfer, como una biblioteca C de un tercero.
4

Bueno, si simplemente necesita un conjunto de caracteres, std :: string ofrece pocas ventajas. Pero enfréntalo, ¿con qué frecuencia es ese el caso? Al envolver una matriz char con funcionalidades adicionales como std :: string, usted gana potencia y eficiencia para algunas operaciones.

Por ejemplo, determinar la longitud de una matriz de caracteres requiere "contar" los caracteres en la matriz. Por el contrario, std :: string proporciona una operación eficiente para esta tarea en particular. (Ver https://stackoverflow.com/a/1467497/129622)

  1. por el poder, la eficiencia y la cordura
  2. huella de memoria más grande que "sólo" una matriz de caracteres
  3. Cuando simplemente necesita un conjunto de caracteres
2

3) El consejo siempre use string, por supuesto, debe tomarse con una pizca de sentido común. Los literales de cadena son const char[], y si pasa un literal a una función que toma un const char* (por ejemplo std::ifstream::open()), no tiene sentido enarbolarlo en std::string.

-1

En general, siempre se debe usar std :: string, ya que es menos propenso a errores. Tenga en cuenta que la sobrecarga de memoria de std :: string es significativa. Recientemente realicé algunos experimentos sobre la sobrecarga de std :: string. En general, ¡tiene alrededor de 48 bytes! El artículo está aquí: http://jovislab.com/blog/?p=76.

+1

Una pena que la optimización de cadenas pequeñas sea una gran cosa. – Puppy

+0

Todo depende de la implementación. Pero en la práctica, sin cosas de depuración, lo escuchado debería ser insignificante. –

+0

* Es * significativo. Con -O2 y sin ninguna -g, G ++ aún toma 24 bytes para una cadena en byte. Supongo que lo mismo es para Visual Studio. – asanoki

1

Un char * es básicamente un puntero a un personaje. Lo que C hace con frecuencia hace que este puntero apunte al primer carácter de una matriz.

Una std :: string es una clase que se parece mucho a un vector.Internamente, maneja el almacenamiento de una matriz de caracteres, y le da al usuario varias funciones miembro para manipular dicha matriz almacenada, así como varios operadores sobrecargados.

razones para utilizar un char * sobre un std :: string:

C backwards-compatibility. 
Performance (potentially). 
char*s have lower-level access. 

razones para utilizar un std :: string en un char *:

Much more intuitive to use. 
Better searching, replacement, and manipulation functions. 
Reduced risk of segmentation faults. 

Ejemplo:

char * se debe usar junto con una matriz char o con una matriz char asignada dinámicamente. Después de todo, un puntero es inútil a menos que realmente apunte a algo. Esto se usa principalmente en programas C:

char somebuffer[100] = "a string"; 
char* ptr = somebuffer; // ptr now points to somebuffer 
cout << ptr; // prints "a string" 
somebuffer[0] = 'b'; // change somebuffer 
cout << ptr; // prints "b string" 

, tenga en cuenta que cuando cambie 'somebuffer', 'ptr' también cambiará. Esto se debe a que somebuffer es la cadena real en este caso. ptr just points/se refiere a eso.

Con std :: string es menos raro:

std::string a = "a string"; 
std::string b = a; 
cout << b; // prints "a string" 
a[0] = 'b'; // change 'a' 
cout << b; // prints "a string" (not "b string") 

Aquí, se puede ver que el cambio 'a' no afecta 'b', porque 'b' es la cadena real.

Pero en realidad, la principal diferencia es que con las matrices de caracteres, usted es responsable de administrar la memoria, mientras que std :: string lo hace por usted. En C++, hay muy pocas razones para usar matrices de caracteres sobre cadenas. 99 veces de cada 100 estás mejor con una cuerda.

Hasta que comprenda completamente la administración de la memoria y los indicadores, simplemente ahórrese algunos dolores de cabeza y use std :: string.

+0

Dudo la afirmación sobre un mejor rendimiento de las cadenas C. * * Tiene menos sobrecarga de memoria, lo que puede ser crucial si tiene muchas cadenas pequeñas (por ejemplo, en análisis sintáctico o bioinformática, donde 'std :: string' puede ser prohibitivo). –

+0

El uso de char * le brinda más control sobre lo que está sucediendo "detrás" de las escenas, lo que significa que puede ajustar el rendimiento si lo necesita. –

1

¿Por qué debería uno usar std :: string sobre cadenas c-style en C++?

La razón principal es que le libera de administrar la vida útil de los datos de cadena. Puede tratar cadenas como valores y dejar que el compilador/biblioteca se preocupe por la administración de la memoria.

Administrar manualmente las asignaciones de memoria y el tiempo de vida es tedioso y propenso a errores.

¿Cuáles son las desventajas (si las hay) de la práctica mencionada en el n. ° 1?

Olvidas el control detallado de la asignación y copia de la memoria. Eso significa que terminas con una estrategia de gestión de memoria elegida por tu proveedor de la cadena de herramientas en lugar de elegida para que coincida con las necesidades de tu programa.

Si no se tiene cuidado puede terminar con un montón de copia de datos que no sean necesarios (en una implementación no refcounted) o manipulación cuenta de referencia (en una implementación refcounted)

En un proyecto de lenguaje mixto cualquier función cuyos argumentos usan std :: string o cualquier estructura de datos que contenga std :: string no podrá ser utilizada directamente desde otros lenguajes.

¿Cuáles son los escenarios donde lo contrario de los consejos mencionados en el n. ° 1 es una buena práctica?

Diferentes personas tienen diferentes opiniones sobre esto, pero la OMI

  • Para argumentos de la función que pasan cuerdas en "const char *" es una buena opción ya que evita unnessacery copia/refcouning y le da la flexibilidad de llamadas acerca lo que pasan.
  • Para las cosas que se usan en interoperación con otros idiomas, no tiene más remedio que utilizar cadenas de estilo c.
  • Cuando tiene un límite de longitud conocido, puede ser más rápido utilizar arreglos de tamaño fijo.
  • cuando se trata de cadenas muy largas, puede ser mejor usar una construcción que será sin duda refcounted en lugar de copiar (tal como una matriz de caracteres envuelto en una shared_ptr) o de hecho de usar un tipo diferente de estructura de datos en conjunto
Cuestiones relacionadas