¿Por qué no las clases std :: fstream toman std :: string?

Esta no es una cuestión de diseño, en realidad, aunque parezca así. (Bueno, está bien, es una especie de pregunta de diseño). Lo que me pregunto es por qué las clases C ++ std::fstream no toman una std::string en su constructor o métodos abiertos. A todos les gustan los ejemplos de código así que:

 #include  #include  #include  int main() { std::string filename = "testfile"; std::ifstream fin; fin.open(filename.c_str()); // Works just fine. fin.close(); //fin.open(filename); // Error: no such method. //fin.close(); } 

Esto me pone todo el tiempo cuando trabajo con archivos. Seguramente, la biblioteca C ++ usaría std::string siempre que sea posible.

Al tomar una cadena C, la clase C ++ 03 std::fstream redujo la dependencia en la clase std::string . En C ++ 11, sin embargo, la clase std::fstream permite pasar una std::string para su parámetro de constructor.

Ahora, puede que se pregunte por qué no hay una conversión transparente de std:string a C, por lo que una clase que espera una cadena C podría tomar std::string igual que una clase que espera std::string puede tomar una cadena C

La razón es que esto provocaría un ciclo de conversión, que a su vez puede generar problemas. Por ejemplo, supongamos que std::string sería convertible en una cadena C para que pueda usar std::string s con fstream s. Supongamos también que la cadena C es convertible a std::string s como es el estado en el estándar actual. Ahora, considere lo siguiente:

 void f(std::string str1, std::string str2); void f(char* cstr1, char* cstr2); void g() { char* cstr = "abc"; std::string str = "def"; f(cstr, str); // ERROR: ambiguous } 

Como puede convertir de cualquier manera entre una std::string y una cadena C, la llamada a f() podría resolverse en cualquiera de las dos alternativas f() , y por lo tanto es ambigua. La solución es romper el ciclo de conversión haciendo explícita una dirección de conversión, que es lo que STL eligió hacer con c_str() .

Hay varios lugares donde el comité estándar de C ++ realmente no optimizó la interacción entre las instalaciones en la biblioteca estándar.

std::string y su uso en la biblioteca es uno de estos.

Otro ejemplo es std::swap . Muchos contenedores tienen una función de miembro de intercambio, pero no se proporciona una sobrecarga de std :: swap. Lo mismo std::sort para std::sort .

Espero que todas estas pequeñas cosas se arreglen en el próximo estándar.

Tal vez sea un consuelo: todos los fstream han obtenido un open (const de cadena &, …) al lado del open (char const *, …) en el borrador de trabajo del estándar C ++ 0x. (ver, por ejemplo, 27.8.1.6 para la statement basic_ifstream)

Entonces, cuando se finalice e implemente, no te conseguirá más 🙂

La biblioteca de flujo IO se ha agregado a la biblioteca estándar de C ++ antes del STL. Para no romper la compatibilidad con versiones anteriores, se ha decidido evitar la modificación de la biblioteca IO cuando se agregó el STL, incluso si eso implicaba problemas como el que usted plantea.

@ Bernard:
Monolitos “Unstrung”. “Todos para uno, y uno para todos” puede funcionar para los mosqueteros, pero no funciona tan bien para los diseñadores de clase. Aquí hay un ejemplo que no es del todo ejemplar, e ilustra qué tan mal puede salir mal cuando el diseño se convierte en sobrediseño. El ejemplo es, lamentablemente, tomado de una biblioteca estándar cerca de usted … ~ http://www.gotw.ca/gotw/084.htm

Es inconsecuente, eso es verdad. ¿A qué te refieres con que la interfaz de std :: string sea grande? ¿Qué significa grande, en este contexto, muchas llamadas a métodos? No estoy siendo gracioso, en realidad estoy interesado.

Tiene más métodos de los que realmente necesita, y su comportamiento de usar desplazamientos integrales en lugar de iteradores es un poco dudoso (ya que es contrario a la forma en que funciona el rest de la biblioteca).

El verdadero problema, creo, es que la biblioteca de C ++ tiene tres partes; tiene la antigua biblioteca C, tiene el STL y tiene strings-and-iostreams. Aunque se hicieron algunos esfuerzos para unir las diferentes partes (por ejemplo, la adición de sobrecargas a la biblioteca C, porque C ++ admite sobrecarga, la adición de iteradores a cadena básica, la adición de los adaptadores iteradores iostream), hay muchas inconsistencias cuando mira el detalle.

Por ejemplo, basic_string incluye métodos que son duplicados innecesarios de algoritmos estándar; los diversos métodos de búsqueda, probablemente podrían eliminarse de forma segura. Otro ejemplo: las configuraciones regionales usan punteros sin formato en lugar de iteradores.

C ++ creció en máquinas más pequeñas que los monstruos para los que escribimos el código hoy. Cuando iostream era nuevo, muchos desarrolladores realmente se preocupaban por el tamaño del código (tenían que ajustar todo su progtwig y datos en varios cientos de KB). Por lo tanto, muchos no quisieron incorporar la “gran” biblioteca de cadenas C ++. Muchos ni siquiera usaron la biblioteca iostream por las mismas razones, el tamaño del código.

No teníamos miles de megabytes de RAM para lanzar como lo hacemos hoy. Por lo general, no teníamos un enlace a nivel de función, por lo que estábamos a merced del desarrollador de la biblioteca para usar muchos archivos de objetos separados o bien obtener toneladas de código no llamado. Todo este FUD hizo que los desarrolladores se alejaran de std :: string.

En aquel entonces evité std :: string también. “Demasiado hinchado”, “llamado malloc con demasiada frecuencia”, etc. Tontamente, utiliza búferes basados ​​en stack para cadenas, y luego agrega todo tipo de código tedioso para asegurarse de que no se sobrepase.

¿Hay alguna clase en STL que tome una cadena? No lo creo (no pude encontrar ninguna en mi búsqueda rápida). Entonces, probablemente sea una decisión de diseño, que ninguna clase en STL debería depender de ninguna otra clase de STL (que no sea directamente necesaria para la funcionalidad).

Creo que esto se ha pensado y se hizo para evitar la dependencia; es decir, #include no debería obligar a uno a #incluir .

Para ser honesto, esto parece un problema bastante intrascendente. Una mejor pregunta sería, ¿por qué la interfaz de std :: string es tan grande?

Hoy en día puede resolver este problema muy fácilmente: agregue -std=c++11 a su CFLAGS .