programas - para que sirve c++
¿Por qué la biblioteca estándar de C++ ya no está incluida en ninguna fuente de C++? (7)
Bueno, primero lo primero, C ++ intenta adherirse a "solo pagas por lo que usas".
La biblioteca estándar a veces no forma parte de lo que usa en absoluto, ni siquiera de lo que podría usar si lo desea.
Además, puede reemplazarlo si hay una razón para hacerlo: consulte libstdc++
y libc++
.
Eso significa que simplemente incluirlo todo sin preguntar no es realmente una idea brillante.
De todos modos, el comité está lentamente intentando crear un sistema de módulos (se necesita mucho tiempo, espero que funcione para los módulos C ++ 1z: C ++. ¿Por qué se eliminaron de C ++ 0x? ¿Volverán más tarde? ? ), y cuando se hace eso, la mayoría de los inconvenientes para incluir más de la biblioteca estándar de lo que es estrictamente necesario debería desaparecer, y los módulos individuales deberían excluir de forma más clara los símbolos que no deben contener.
Además, como esos módulos se analizan previamente, deben proporcionar la mejora de velocidad de compilación que desee.
En C ++, la biblioteca estándar está envuelta en el std
nombres estándar y el programador no debe definir nada dentro de ese espacio de nombres. Por supuesto, los archivos de inclusión estándar no interfieren entre sí nombres dentro de la biblioteca estándar (por lo que nunca es un problema incluir un encabezado estándar).
Entonces, ¿por qué no se incluye por defecto toda la biblioteca estándar en lugar de forzar a los programadores a escribir, por ejemplo, #include <vector>
cada vez? Esto también aceleraría la compilación ya que los compiladores podrían comenzar con una tabla de símbolos preconstruida para todos los encabezados estándar.
Preincluir todo también resolvería algunos problemas de portabilidad: por ejemplo, cuando se incluye <map>
se definen qué símbolos se toman en el std
nombres estándar, pero no se garantiza que no se carguen otros símbolos estándar y, por ejemplo, podría terminar ( en teoría) con std::vector
también disponible.
Ocurre a veces que un programador olvida incluir un encabezado estándar, pero el programa se compila de todos modos debido a la dependencia de incluir la implementación específica. Al mover el programa a otro entorno (o simplemente a otra versión del mismo compilador), el mismo código fuente podría dejar de compilar.
Desde un punto de vista técnico, puedo crear una imagen de un compilador que acaba de precargar (con mmap
) una tabla de símbolos perfecta de hash perfecto para la biblioteca estándar. Esto debería ser más rápido que cargar y realizar un análisis en C ++ de incluso un solo archivo de inclusión estándar y debería ser capaz de proporcionar una búsqueda más rápida de std::
names. Esta información también sería de solo lectura (lo que probablemente permita una representación más compacta y también compartible entre varias instancias del compilador).
Sin embargo, estos son solo porque nunca lo implementé.
El único inconveniente que veo es que los programadores de C ++ perderíamos coffee breaks de compilación y visitamos Stack Overflow :-)
EDITAR
Solo para aclarar, la principal ventaja que veo es que los programadores que hoy, a pesar de que la biblioteca estándar de C ++ sea un único espacio de nombres monolítico, necesiten saber qué subparte (incluir archivo) contiene qué función / clase. Para colmo de males cuando se equivocan y olvidan un archivo de inclusión, el código puede compilarse o no según la implementación (lo que lleva a programas no portátiles).
Creo que la respuesta se reduce a la filosofía de C ++ de no hacer que pagues por lo que no usas. También le da más flexibilidad: no está obligado a usar partes de la biblioteca estándar si no las necesita. Y luego está el hecho de que algunas plataformas pueden no ser compatibles con cosas como lanzar excepciones o asignar dinámicamente la memoria (como los procesadores utilizados en el Arduino, por ejemplo). Y hay otra cosa que dijiste que es incorrecta. Siempre que no sea una clase de plantilla, puede agregar operadores de swap
al espacio de nombres std
para sus propias clases.
En primer lugar, me temo que tener un preludio es un poco tarde para el juego. O más bien, dado que los preludios no son fácilmente extensibles, tenemos que contentarnos con uno muy delgado (tipos incorporados ...).
Como ejemplo, digamos que tengo un programa C ++ 03:
#include <boost/unordered_map.hpp>
using namespace std;
using boost::unordered_map;
static unordered_map<int, string> const Symbols = ...;
Todo funciona bien, pero de repente cuando migro a C ++ 11:
error: ambiguous symbol "unordered_map", do you mean:
- std::unordered_map
- boost::unordered_map
Enhorabuena, has inventado el esquema menos retrocompatible para hacer crecer la biblioteca estándar (es broma, quien usa el using namespace std;
estándar using namespace std;
es el culpable ...).
De acuerdo, no los preincluyamos, pero aun así empaquetamos la tabla hash perfecta de todos modos. La ganancia de rendimiento valdría la pena, ¿verdad?
Bueno, lo dudo seriamente. En primer lugar, porque la Biblioteca estándar es pequeña comparada con la mayoría de los otros archivos de cabecera que incluye (sugerencia: compárela con Boost). Por lo tanto, la ganancia de rendimiento sería ... pequeña.
Oh, no todos los programas son grandes; pero los pequeños ya se compilan rápido (en virtud de ser pequeños) y los más grandes incluyen mucho más código que los encabezados de la Biblioteca estándar, por lo que no sacará mucho provecho de ello.
Nota: y sí, comparé la búsqueda de archivos en un proyecto con "solo" cien directivas; la conclusión fue que pre-computar el mapa de "incluir camino" a "ubicación de archivo" y alimentarlo a gcc dio como resultado una aceleración del 30% (después de usar ccache ya). Generarlo y mantenerlo actualizado fue complicado, por lo que nunca lo usamos ...
Pero, ¿podríamos al menos incluir una disposición que el compilador podría hacer en el Estándar?
Por lo que sé, ya está incluido. No puedo recordar si hay una propaganda específica al respecto, pero la Biblioteca estándar es realmente parte de la "implementación", por lo que resolver #include <vector>
a un hash-map interno quedaría bajo la regla de si-y-si.
Pero podrían hacerlo, ¡todavía!
Y pierda flexibilidad. Por ejemplo, Clang puede usar libstdc ++ o libc ++ en Linux, y creo que es compatible con la derivada de Dirkumware que se envía con VC ++ (o si no completamente, al menos en gran medida).
Este es otro punto de personalización: si la biblioteca estándar no se ajusta a sus necesidades, o sus plataformas, en virtud de que se trata principalmente como cualquier otra biblioteca, puede reemplazar parte de la mayoría con relativa facilidad.
¡Pero! ¡Pero!
#include <stdafx.h>
Si trabajas en Windows, lo reconocerás. Esto se llama un encabezado precompilado. Debe incluirse primero (o se perderán todos los beneficios) y, a cambio, en lugar de analizar los archivos, está obteniendo una representación binaria eficiente de esos archivos analizados (es decir, una versión AST serializada, posiblemente con algún tipo de resolución ya realizada) que salva Tal vez del 30% al 50% del trabajo. Sí, esto está cerca de su propuesta; esto es informática para ti, siempre hay alguien más que lo pensó primero ...
Clang y gcc tienen un mecanismo similar; aunque por lo que he escuchado puede ser tan doloroso de usar que las personas prefieren la cocaína más transparente en la práctica.
Y todo esto no servirá para nada con los módulos .
Esta es la verdadera solución para esta locura de preprocesamiento / análisis / resolución de tipos. Debido a que los módulos están verdaderamente aislados (es decir, a diferencia de los encabezados, no están sujetos al orden de inclusión), se puede calcular previamente una representación binaria eficiente (como los encabezados precompilados) para cada uno de los módulos de los que dependa .
Esto no solo significa la biblioteca estándar, sino todas las bibliotecas .
Tu solución, más flexible, y vestida a la perfección!
La mayoría de las bibliotecas estándar de C ++ están basadas en plantillas, lo que significa que el código que generarán dependerá en última instancia de cómo las use. En otras palabras, hay muy poco que se pueda compilar antes de instanciar una plantilla como std::vector<MyType> m_collection;
.
Además, C ++ es probablemente el lenguaje más lento para compilar y hay mucho trabajo de análisis que los compiladores tienen que hacer cuando #include
un archivo de encabezado que también incluye otros encabezados.
La respuesta corta se debe a que no es la forma en que se supone que se debe usar el lenguaje C ++
Hay buenas razones para eso:
- contaminación del espacio de nombres - incluso si esto podría ser mitigado porque se supone que el espacio de nombres estándar es auto coherente y el programador no está obligado a usar el
using namespace std;
. Pero incluyendo toda la biblioteca con elusing namespace std;
sin duda dará lugar a un gran lío ... - obligar al programador a declarar los módulos que quiere usar para evitar llamar inadvertidamente una función estándar incorrecta porque la biblioteca estándar ahora es enorme y no todos los programadores saben todos los módulos
- history: C ++ todavía tiene una fuerte herencia de C, donde el espacio de nombres no existe y donde se supone que la biblioteca estándar debe usarse como cualquier otra biblioteca.
Para ir en tu sentido, la API de Windows es un ejemplo donde solo tienes una gran inclusión (windows.h) que carga muchos otros archivos de inclusión más pequeños. Y, de hecho, los encabezados precompilados permiten que sea lo suficientemente rápido
Entonces, en mi humilde opinión, un nuevo lenguaje derivado de C ++ podría decidir declarar automáticamente toda la biblioteca estándar. Una nueva versión principal también podría hacerlo, pero podría romper el código de manera intensiva utilizando la directiva de using namespace
y tener implementaciones personalizadas con los mismos nombres que algunos módulos estándar.
Pero todos los lenguajes comunes que conozco (C #, Python, Java, Ruby) requieren que el programador declare las partes de la biblioteca estándar que quiere usar, así que supongo que hacer que cada parte de la biblioteca estándar esté disponible sistemáticamente es aún más incómodo. que realmente útil para el programador, al menos hasta que alguien encuentre cómo declarar las partes que no deberían cargarse, es por eso que hablé de una nueva derivada de C ++
Se podría usar una implementación alternativa de la biblioteca estándar de C ++ a la que se incluye con el compilador. O envuelva los encabezados con las definiciones propias, para agregar, habilitar o deshabilitar características (consulte los encabezados del contenedor GNU). Los encabezados de texto simple y el modelo de inclusión C son un mecanismo más poderoso y flexible que una caja negra binaria.
Usted ofrece dos ventajas de su esquema:
Rendimiento en tiempo de compilación. Pero nada en el estándar impide que una implementación haga lo que sugiere [*] con una modificación muy leve: que la tabla precompilada solo se asigna cuando la unidad de traducción incluye al menos un encabezado estándar. A partir del punto de vista del estándar, no es necesario imponer una carga de implementación potencial sobre un problema de QoI.
Conveniencia para los programadores: según su esquema, no tendríamos que especificar qué encabezados necesitamos. Hacemos esto para respaldar las implementaciones de C ++ que han elegido no implementar su idea de hacer que los encabezados estándar sean monolíticos (que actualmente son todos) y, por lo tanto, desde el POV del estándar C ++ es una cuestión de "respaldar la práctica existente y libertad de implementación a un costo para los programadores considerados aceptables ". ¿Cuál es el eslogan de C ++, no?
Dado que ninguna implementación de C ++ (que yo sepa) realmente hace esto, mi sospecha es que, de hecho, no garantiza la mejora en el rendimiento que crees que tiene. Microsoft proporciona encabezados precompilados (a través de stdafx.h
) exactamente por esta razón de rendimiento, y aún así no le da una opción para "todas las bibliotecas estándar", sino que requiere que diga lo que quiere. Estaría muerto Es fácil para esta u otra implementación proporcionar un encabezado específico de implementación definido para tener el mismo efecto que incluir todos los encabezados estándar. Esto me sugiere que, al menos en la opinión de Microsoft, no sería un gran beneficio general proporcionarlo.
Si las implementaciones comenzaran a proporcionar bibliotecas estándar monolíticas con una mejora demostrable del rendimiento en tiempo de compilación, entonces discutiremos si es o no una buena idea que el estándar C ++ continúe permitiendo implementaciones que no lo hacen. Tal como están las cosas, tiene que hacerlo.
[*] Excepto quizás por el hecho de que se define que <cassert>
tiene un comportamiento diferente según la definición de NDEBUG
en el punto en que está incluido. Pero creo que las implementaciones podrían simplemente preprocesar el código del usuario como normal, y luego asignar en una de dos tablas diferentes según esté definido.