librerias - ¿Requiere un cierto orden para#includes en c++ un signo de mal diseño de biblioteca/encabezado?
librerias estandar de c++ (13)
¿La biblioteca STL o STD o incluso Boost tienen algún caso en el que ciertos includes deben venir en cierto orden?
Para el estándar, la respuesta es enfáticamente, no . Imagino lo mismo para Boost, aunque no lo he buscado.
Del estándar C:
Los encabezados estándar pueden incluirse en cualquier orden; cada uno puede incluirse más de una vez en un ámbito determinado, sin ningún efecto diferente de ser incluido solo una vez, excepto que el efecto de incluir
<assert.h>
depende de la definición deNDEBUG
(ver 7.2).
el estándar de C ++ tiene una redacción similar.
Mi preferencia es que los encabezados incluyan sus propias dependencias, pero he trabajado con personas que creen que esto es "un desperdicio". En mi opinión, no tener encabezados que incluyan sus dependencias es una optimización temprana inútil.
He usado algunos sistemas de gran escala y nunca he visto un pedido obligatorio, pero lo encontré recientemente. ¿La biblioteca STL o STD o incluso Boost tienen algún caso en el que ciertos includes deben venir en cierto orden?
¿La biblioteca STL o STD o incluso Boost tienen algún caso en el que ciertos includes deben venir en un cierto orden?
Nunca me he encontrado con esto y si es así, los autores deben ser notificados lo antes posible. Y oh sí, es un diseño muy malo.
Esto definitivamente suena como un mal diseño. Si de alguna manera se requiere un pedido específico, la biblioteca debe proporcionar un encabezado que incluya los otros en el orden correcto .
En cuanto al impulso, y el STL, estoy bastante seguro de que aún no me he encontrado con esta situación.
La necesidad de especificar incluye en un orden específico casi siempre indica un problema de diseño. Una forma de reducir la posibilidad de hacer esto inadvertidamente es entrar en la práctica de incluir el archivo de encabezado de una clase como el primer #include en el archivo de implementación.
// A.cpp
#include "A.h"
#include "boost/shared_ptr.hpp"
#include <vector>
class A {
// ...
};
De esta forma, si, por ejemplo, Ah usa un vector sin el #include correcto, A.cpp no compilará.
No puedo recordar dónde recogí esto; podría haber sido del "Diseño a gran escala de C ++" de Lakos (un gran libro que realmente podría usar una actualización).
Me gusta incluir encabezados en orden alfabético, hace que sea fácil ver lo que ya hice.
Si una lib no funciona porque está en el orden incorrecto, está rota y se debe corregir para que sea independiente de la orden.
No que yo sepa. Es una mala práctica. Sin embargo, me he encontrado con un encabezado de Windows y una interfaz extraña en mi código recientemente.
Si las funciones y / o clases contenidas en el encabezado (por ejemplo, Ah) dependen de funciones y / o clases definidas en otro encabezado (por ejemplo, Bh), prefiero incluir el último en el primero, en lugar de forzar a los usuarios del primero uno para incluir ambos en un orden particular.
Sí:
// A.h
#pragma once
// or the #ifndef trick
#include "B.h"
// A.cpp
#include "A.h"
No:
// A.h
#pragma once
// or the #ifndef trick
//#include "B.h"
// A.cpp
#include "B.h"
#include "A.h"
Deberías usar guardias include y declaraciones forward, de esa manera no deberías tener muchos problemas con el orden de incluir encabezados.
A veces todavía se requiere que se incluya un encabezado primero o último, ni idea de por qué.
(Por ejemplo: en Source SDK)
Es quizás una señal de que estás usando MFC, lo que a su vez podría indicar un mal diseño (broma ... ¿o no?)
(Al menos, la última vez que miré en MFC, fue muy delicado acerca de dónde incluía <windows.h>
)
Es una técnica común incluir un encabezado de compatibilidad de nivel de proyecto (digamos compat.h) como el primer encabezado de cualquier archivo fuente .c / .cpp, que define un conjunto de macros requeridas como __STDC_LIMIT_MACROS, __REENTRANT y otras macros de proyecto para afectar el comportamiento posterior de los encabezados estándar.
La primera vez que vi este uso fue hace mucho tiempo por un programador competente para una biblioteca interna. Más tarde vi el proyecto ''git'' (el infame DVD) usar esta técnica también.
Para mí es un mal diseño que, desafortunadamente, pasa a estar en la API win32 con socket / socket2 incluye, si no recuerdo mal. El resultado es que un error en el orden de inclusión desencadenará un conjunto de errores que simplemente provienen de la nada y puede ser difícil de depurar en los casos en que la dependencia cambia las definiciones pero el código aún se compila.
En cualquier otro caso, todavía te encontrarás con problemas. Si no incluye el encabezado xh porque yh ya lo incluye, entonces su código depende de la dependencia de yh en xh Si en un momento posterior yh es refactorizado y ya no requiere yh, la eliminación del include romperá su base de código. Este es un signo de acoplamiento (incluso si no a nivel de clase): los cambios en una parte de la base de código necesitan propagarse y extenderse a otras partes del código.
Eso es malo''. Se ha mencionado una mejor manera; pero lo elaboraré.
//a.h #ifndef _A_H_ #define _A_H_ //... code ... #endif // ----------------- //b.h #ifndef _B_H_ #define _B_H_ #include a.h //... code ... #endif // ----------------- //main.cpp Try 1 #include "b.h" //<- okay! b includes a, then does b // ----------------- //main.cpp Try 2 #include "a.h" //<- includes a #include "b.h" //<- okay! b includes a, but skips redefining it, then does b // ----------------- //main.cpp Try 3 #include "b.h" //<- b includes a, then does b #include "a.h" //<- okay! a skips redefining itself! // ----------------- //main.cpp Try 4 #include "a.h" //<- fail! b is not included anywhere =(
Sí, requerir un cierto orden para incluir en c ++ es un signo de mal diseño de la biblioteca / encabezado.
Aunque las declaraciones anticipadas pueden requerir que se incluya más de un archivo para usar completamente una clase. Vea el siguiente ejemplo:
// Ah
class B; // forward declaration
class A
{
void doStuff(const B& b);
};
// main.cpp
#include <A.h>
#include <B.h>
int main()
{
A a;
B b;
a.doStuff(b);
}