good - C++ genera confusión: istreambuf_iterator vs istream_iterator?
ifstream>> (2)
¿Cuál es la diferencia entre istreambuf_iterator
e istream_iterator
? Y en general, ¿cuál es la diferencia entre streams y streambufs? Realmente no puedo encontrar una explicación clara para esto, así que decidí preguntar aquí.
Este es un secreto muy mal guardado: un iostream per se , casi no tiene nada que ver con leer o escribir desde / hacia un archivo en su computadora.
Un iostream básicamente actúa como un "casamentera" entre un streambuf y un locale:
El iostream almacena algún estado sobre cómo se deben realizar las conversiones (por ejemplo, el ancho y la precisión actuales para una conversión). Utiliza esos para dirigir la configuración regional cómo y dónde hacer una conversión (por ejemplo, convertir este número a una cadena en ese búfer con ancho 8 y precisión 5).
A pesar de que no le preguntó directamente al respecto, la configuración regional en realidad es solo un contenedor, pero (más bien una rareza) un contenedor heterogéneo tipo seguro. Las cosas que contiene son facet
. Un objeto de faceta define una sola faceta de una configuración regional general. El estándar define una cantidad de facetas para todo, desde leer y escribir números ( num_get
, num_put
) hasta clasificar caracteres (la faceta ctype).
De forma predeterminada, una secuencia usará la configuración regional "C". Esto es bastante básico: los números se convierten simplemente como una secuencia de dígitos, las únicas cosas que reconoce son letras, 26 letras minúsculas y 26 letras mayúsculas en inglés, y así sucesivamente. Sin embargo, puede imbue
una secuencia con una configuración regional diferente de su elección. Puede elegir las configuraciones regionales para usar por nombres especificados en cadenas. Uno que es particularmente interesante es uno que se selecciona con una cadena vacía. El uso de una cadena vacía básicamente le dice a la biblioteca de tiempo de ejecución que seleccione la configuración regional que "piensa" es la más adecuada, generalmente en función de cómo el usuario ha configurado el sistema operativo. Esto permite que el código trate los datos en un formato localizado sin que se escriban explícitamente para una configuración regional en particular.
Entonces, la diferencia básica entre un istream_iterator
y un istreambuf_iterator
es que los datos que salen de un istreambuf_iterator no han pasado (la mayoría de) las transformaciones hechas por el entorno local, pero los datos que salen de un istream_iterator
han sido transformados por el entorno local.
Por lo que vale, que "la mayoría de" en el párrafo anterior se refiere al hecho de que cuando se leen datos de un istreambuf (a través de un iterador u otro) se realiza una pequeña transformación basada en la configuración regional: junto con varios " formateando "tipos de cosas", la configuración regional contiene una faceta codecvt, que es lo que se usa para convertir de una representación externa a una representación interna (por ejemplo, UTF-8 a UTF-32).
Puede tener más sentido ignorar el hecho de que ambos están almacenados en un lugar, y pensar solo en las facetas individuales involucradas:
istream_iterator
es la verdadera diferencia entre un istream_iterator
y un istreambuf_iterator
. Un poco de transformación es (al menos potencialmente) hecho a los datos de cualquiera de los dos, pero se hace mucho menos a los datos provenientes de un istreambuf_iterator
.
IOstream usa streambufs como su fuente / destino de entrada / salida. Efectivamente, la familia streambuf hace todo el trabajo con respecto a IO y la familia IOstream solo se usa para el formateo y para la cadena de caracteres / transformación de cadena.
Ahora, istream_iterator
toma un argumento de plantilla que dice de qué forma se debe formatear la secuencia de cadena sin formato del streambuf, como istream_iterator<int>
interpretará (delimitado por espacios en blanco) todo el texto entrante como int
.
Por otro lado, istreambuf_iterator
solo se preocupa por los caracteres sin procesar e itera directamente sobre el streambuf asociado del istream
que se pasa.
En general, si solo está interesado en los caracteres sin istreambuf_iterator
, use un istreambuf_iterator
. Si está interesado en la entrada formateada, use un istream_iterator
.
Todo lo que dije también se aplica a ostream_iterator
y ostreambuf_iterator
.