2008-09-20 16 views
18

¿Hay alguna buena razón para usar C-strings en C++ hoy en día? Mi libro de texto los usa en ejemplos en algunos puntos, y realmente siento que sería más fácil simplemente usar una std :: string.¿Por qué usar c cadenas en C++?

Respuesta

22

La única razón por la que he tenido que usarlos es cuando me comunico con bibliotecas de terceros que usan cadenas de estilo C. También podría haber situaciones esotéricas en las que usaría cadenas de estilo C por motivos de rendimiento, pero la mayoría de las veces, usar métodos en cadenas de C++ es probablemente más rápido debido a la creación y especialización, etc.

Puede usar el método c_str() en muchos casos cuando se trabaja con ese tipo de API, pero debe tener en cuenta que el carácter * devuelto es const, y no debe modificar la cadena a través de ese puntero. En ese tipo de situaciones, puede utilizar un vector <char> en su lugar, y al menos obtener el beneficio de una administración de memoria más sencilla.

+3

El valor de retorno es const por un motivo. Modificarlo usando un const_cast o Ccast es la desincronización del estado interno del objeto. Debería decir "no debe modificar", no "no debería". – Thorsten79

8

Porque eso es la forma en que proceden de numerosas API/bibliotecas?

0

Las cadenas STL son mucho más fáciles de usar y no veo ninguna razón para no utilizarlas.

Si necesita interactuar con una biblioteca que solo utiliza cadenas tipo C como argumentos, siempre puede llamar al método c_str() de la clase de cadena.

+0

El único problema con c_str() es que el puntero que recibe es const. Se supone que no debes modificar los contenidos a través de esa cadena. En situaciones como esa, también puede usar un vector y obtener muchos de los beneficios. – dvorak

+0

Entendido, me refería a pasar las cuerdas a la biblioteca y no sacarlas. –

3

Digamos que tiene algunas constantes de cadena en su código, que es una necesidad bastante común. Es mejor definirlos como cadenas C que como objetos C++, más livianos, portátiles, etc. Ahora, si va a pasar estas cadenas a varias funciones, es bueno si estas funciones aceptan una cadena C en lugar de requerir un Objeto de cadena C++.

Por supuesto, si las cadenas son mutables, entonces es mucho más conveniente usar objetos de cadenas C++.

+3

Tenga en cuenta que las mismas funciones que aceptan un objeto de cadena C++ aceptarían la cadena C de todos modos debido a la construcción implícita, por lo tanto, no hay razón para tener esas funciones alrededor. En cuanto a "más ligero" y "más portátil", el precio a pagar es tener punteros (y tener que probarlos). Para mí ... – paercebal

+0

es cierto que algunas funciones aceptarán un objeto de cadena C++, pero otras no. también, la construcción implícita tiene un costo de rendimiento. pero sí, hay compensaciones ... – adum

2

Si el código de C++ es "profundo" (cerca del kernel, que depende en gran medida de las bibliotecas de C, etc.) puede usar C strings explícitamente para evitar muchas conversiones dentro y fuera de std :: string. De, si está interactuando con otros dominios de lenguaje (Python, Ruby, etc.) puede hacerlo por la misma razón. De lo contrario, use std :: string.

2

Si una función necesita una cadena constante cadena, aún prefiero usar 'const char *' (o const wchar_t *) incluso si el programa usa std :: string, CString, EString o lo que sea.

Hay demasiadas fuentes de cadenas en una gran base de código para asegurarse que la persona que llama tendrá la cadena como un std :: string y 'const char *' es el denominador común más bajo.

1

Dada la opción, generalmente no hay ninguna razón para elegir cadenas primitivas de C (char*) sobre cadenas de C++ (std::string). Sin embargo, a menudo no tiene el lujo de elegir. Por ejemplo, los constructores de std::fstream toman cadenas C, por razones históricas. Además, las bibliotecas C (¡lo has adivinado!) Usan cadenas C.

En su propio código C++ es mejor usar std::string y extraer la cadena C del objeto según sea necesario utilizando el c_str() function of std::string.

+1

Y, por supuesto, tienes que usar cadenas tipo C para literales de cadenas. – dan04

+0

@ dan04 No necesariamente. dado 'void f (std :: string s);' puede llamar a la función con 'f (" C string ");' porque una cadena C puede convertirse implícitamente en una 'std :: string'. – wilhelmtell

1

Los libros de texto tienen cadenas de caracteres de la vieja escuela porque muchas funciones básicas aún los esperan como argumentos o los devuelven. Además, da una idea de la estructura subyacente de la cadena en la memoria.

1

Depende de las bibliotecas que se está usando.Por ejemplo, cuando se trabaja con el MFC, a menudo es más fácil usar CString cuando se trabaja con varias partes de la API de Windows. También parece funcionar mejor que std :: string en aplicaciones Win32.

Sin embargo, std :: string es parte del estándar de C++, por lo que si desea una mejor portabilidad, vaya con std :: string.

1

Para aplicaciones como la mayoría de las plataformas integradas donde no se puede tener el lujo de almacenar las cadenas que se manipulan, y donde se requiere la asignación previa determinista de almacenamientos intermedios de cadenas.

+1

¿string.reserve() no permite preasignación determinística? –

+0

@Jason - podría ser que tuvieras un montón. – mattnz

1

Las cadenas de caracteres c no suponen la carga de ser una clase.

cadenas de C en general, pueden dar lugar a un código más rápido, ya que están más cerca del nivel de la máquina

Esto no quiere decir, no se puede escribir código malo con ellos. Pueden ser mal utilizados, como cualquier otra construcción.

Hay una gran cantidad de llamadas a la biblioteca que lo exigen por razones históricas.

Aprenda a usar cadenas de caracteres y stl, y use cada una cuando tenga sentido hacerlo.

-2

La razón habitual para hacerlo es que le gusta escribir desbordamientos de búfer en el manejo de cadenas. Las cadenas contadas son tan superiores a las cadenas terminadas que es difícil ver por qué los diseñadores de C alguna vez usaron cadenas terminadas. Fue una mala decisión entonces; es una mala decisión ahora.

+1

Después de haber trabajado con cadenas de estilo pascal (longitud primero) y cadenas de estilo c (terminación nula) he tenido menos problemas con las cadenas c. Ese dicho estilo pascal es más eficiente para algunas operaciones. – maccullt

+0

@DrPizza - No te voté, pero cuando vi tu publicación, supe por qué estaba en -1 ... Personalmente, creo que fue tu fraseología sobre una respuesta. Pero, también estoy de acuerdo con tus comentarios. Sería bueno saber a veces POR QUÉ alguien eligió votar. Tal vez una sugerencia TAN para uso futuro? – LarryF

+1

-1 porque está presentando su opinión como si fuera un hecho. –

3

Control de memoria. Recientemente tuve que manejar cadenas (en realidad blobs de una base de datos) de aproximadamente 200-300 MB de tamaño, en una aplicación de subprocesamiento masivo. Era una situación en la que solo una copia más de la cadena podría haber reventado el espacio de direcciones de 32 bits. Tenía que saber exactamente cuántas copias de la cadena existían. Aunque soy un evangelista de STL, utilicé char * porque me dio la garantía de que no se asignó memoria adicional ni copia adicional. Sabía exactamente cuánto espacio necesitaría.

Aparte de eso, el procesamiento de cadenas STL estándar se pierde en algunas funciones C para el procesamiento/análisis de cadenas. Afortunadamente, std :: string tiene el método c_str() para const acceso al buffer interno. Para usar printf() todavía tienes que usar char * (qué idea tan loca del equipo de C++ es que no incluye (n) la funcionalidad printf, una de las funciones más útiles SIEMPRE en C. Espero que el formato boost :: pronto se incluirán en el STL

+1

funcionalidad sprintf está ahí; solo necesita usar un flujo de cadenas y operadores de salida estándar. – Branan

+0

@Branan: sí, pero no es lo mismo y se vuelve muy incómodo muy rápido si necesita muchos parámetros ... –

14

un par de notas de control de memoria:..

cadenas de C son los tipos de POD, para que puedan ser asignados en el segmento de datos de sólo lectura de la aplicación Si se declara y definir std::string constantes en espacio de nombres, el compilador generará código adicional que se ejecuta antes de main() que llama al constructor std::string para cada constante. Si su aplicación tiene muchas cadenas constantes (por ejemplo, si ha generado código C++ que utiliza cadenas constantes), las cadenas C pueden ser preferibles en th es situación.

Algunas implementaciones de std::string apoyan una función denominada SSO ("optimización de cadena corta" o "optimización de la cadena pequeña") donde la clase std::string contiene almacenamiento para cuerdas hasta una cierta longitud. Esto aumenta el tamaño de std::string pero a menudo reduce significativamente la frecuencia de asignaciones/desasignaciones de tiendas libres, mejorando el rendimiento. Si su implementación de std::string no es compatible con SSO, la construcción de un std::string vacío en la pila aún realizará una asignación de almacenamiento gratuito. Si ese es el caso, usar cadenas C asignadas a la pila temporal puede ser útil para el código de rendimiento crítico que usa cadenas.Por supuesto, debes tener cuidado de no dispararse en el pie cuando hagas esto.

1

Algunas publicaciones mencionan problemas de memoria. Esa podría ser una buena razón para rechazar std :: string, pero char * probablemente no sea el mejor reemplazo. Todavía es un idioma OO. Tu propia clase de cuerda es probablemente mejor que un char *. Incluso puede ser más eficiente: puede aplicar Small String Optimization, por ejemplo.

En mi caso, estaba tratando de obtener alrededor de 1GB de cadenas de un archivo de 2GB, rellenarlas en registros con aproximadamente 60 campos y luego ordenarlos 7 veces en diferentes campos. El código de mis predecesores tomó 25 horas con char *, mi código se ejecutó en 1 hora.

1

1) "cadena constante" es una cadena C (const char *), convirtiéndola en const std :: string & es un proceso en tiempo de ejecución, no necesariamente simple u optimizado. 2) La biblioteca fstream usa cadenas estilo c para pasar nombres de archivo.

Mi regla de oro es pasar const std :: string & si estoy a punto de utilizar los datos como std :: string de todos modos (por ejemplo, cuando los almaceno en un vector), y const char * en otros casos .

2

Después de pasar mucho, mucho, demasiado tiempo depurando reglas de inicialización y cada implementación de cadena concebible en varias plataformas requerimos cadenas estáticas para ser const char *.

Después de pasar mucho, mucho tiempo depurando código de char * malo y pérdidas de memoria sugiero que todas las cadenas no estáticas sean algún tipo de objeto de cadena ... hasta que el perfil demuestre que puede y debe hacer algo mejor; -)

1

Código heredado que no conoce std :: string. Además, antes de C++ 11, la apertura de archivos con std :: ifstream o std :: ofstream solo era posible con const char * como entrada al nombre del archivo.

Cuestiones relacionadas