Compartir por


Limpieza de directivas include de C/C++ en Visual Studio

A partir de la versión preliminar 1 de Visual Studio 17.8, Visual Studio proporciona una característica de limpieza #include que mejora la calidad del código de las formas siguientes:

  • Ofrece la posibilidad de agregar archivos de encabezado para el código que se compila solo porque un archivo de encabezado necesario se incluye indirectamente por otro archivo de encabezado.
  • Ofrece la posibilidad de quitar archivos de encabezado sin usar, lo que mejora los tiempos de compilación y la limpieza de código.

La limpieza de directivas include está activada de forma predeterminada. Para obtener información sobre cómo configurarla, consulte Configuración de la limpieza de directivas include de C/C++ en Visual Studio.

Encabezados directos frente a indirectos

En primer lugar, alguna terminología:

  • Un encabezado directo es un encabezado en el que #include explícitamente en el código.
  • Un encabezado indirecto es un encabezado que no #include explícitamente. En su lugar, un archivo de encabezado que lo incluye directamente, lo incluye. También decimos que se incluye transitively en un encabezado indirecto.

La limpieza de directivas include analiza el código y determina qué encabezados no se usan y cuáles se incluyen indirectamente. Tenga en cuenta el siguiente archivo de encabezado:

// myHeader.h

#include <string>
#include <iostream>

void myFunc()
{
    std::string s = "myFunc()\n";
    std::cout << s;
}

Y el programa que lo usa:

// myProgram.cpp
#include "myHeader.h"

int main()
{
    std::string s = "main()"; // string is indirectly included by myHeader.h
    std::cout << s; // cout is indirectly included by myHeader.h
    myFunc();
}

myHeader.h es un encabezado directo porque myProgram.cpp lo incluye explícitamente. myHeader.h incluye <string> y <iostream>, por lo que son encabezados indirectos.

El problema es que myProgram.cpp usa std::string y std::cout, pero no incluye directamente los encabezados que los definen. Este código se compila porque myHeader.h incluye esos encabezados. Este código es frágil porque si myHeader.h alguna vez se detuviera incluyendo cualquiera, ya myProgram.cpp no se compilaría.

Según las instrucciones de C++, es mejor incluir explícitamente los encabezados para todas las dependencias para que el código no esté sujeto a la fragilidad causada por cambios en los archivos de encabezado. Para obtener más información, consulte C++ Core Guidelines SF.10.

La limpieza de directivas include analiza el código para identificar encabezados sin usar e indirectamente incluidos. Proporciona comentarios basados en la configuración descrita en Configuración de la herramienta #include de C++ en Visual Studio. Puede haber comentarios en forma de advertencias de lista de errores, sugerencias, etc. Para obtener más información sobre los comentarios proporcionados por la limpieza de directivas include, consulte Mensajes de la limpieza de directivas include.

Encabezados sin usar

A medida que el código evolucione, es posible que ya no necesite algunos archivos de encabezado. Esto es algo de lo que resulta difícil realizar un seguimiento en un proyecto complejo. Con el tiempo, las compilaciones podrían tardar más porque el compilador está procesando archivos de encabezado innecesarios. La limpieza de directivas include le ayudará a buscar y quitar encabezados sin usar. Por ejemplo, ¿qué ocurre si myFunc() se comenta en myProgram.cpp:

// myProgram.cpp
#include "myHeader.h"

int main()
{
    std::string s = "main()"; // string is indirectly included from myHeader.h
    std::cout << s; // cout is indirectly included from myHeader.h
    // myFunc(); // directly included from myHeader.h
}

En la captura de pantalla siguiente, #include "myHeader.h" está atenuado (una configuración descrita en Configuración de la herramienta de #include de C++ en Visual Studio) porque no se usa debido a que se comenta myFunc().

Mantenga el cursor sobre el #include atenuado para abrir el menú de acción rápida. Haga clic en la bombilla (o elija el vínculo Mostrar posibles correcciones) para ver las acciones relacionadas con el archivo sin usar:

Three refactoring options are shown: Remove # include myHeader.h, remove all unused includes, and Add all transitively used and remove all unused # includes.

Agregar encabezados usados transitivamente

Podríamos optar por quitar el archivo de encabezado sin usar, pero eso interrumpirá el código, ya que <string> y <iostream> se incluyen indirectamente a través de myheader.h.

En su lugar, se puede elegir Agregar todo el uso transitivo y quitar todos los #includes sin usar. Esto quita el encabezado no utilizado myHeader.h, pero también agrega los encabezados que se usan indirectamente a través de myHeader.h. El resultado, en este caso, está agregando #include <string> y #include <iostream> a myProgram.cpp, además de quitando #include "myHeader.h":

// myProgram.cpp
#include <iostream>
#include <string>

int main()
{
    std::string s = "main()"; // string is directly included from <string>
    std::cout << s; // cout is directly included from <string>
    // MyFunc();
}

La herramienta no actualiza los comentarios, pero se puede ver que el código ahora está usando std::string y std::cout directamente. Este código ya no es frágil porque no depende de myHeader.h que se incluyan los demás encabezados necesarios.

Procedimiento recomendado

No quite lo que parecen ser archivos de encabezado sin usar sin agregar primero archivos de encabezado incluidos indirectamente. Esto se debe a que el código podría depender de inclusiones indirectas en un archivo de encabezado que, de lo contrario, no se use. Agregar primero encabezados usados transitivamente. A continuación, al quitar encabezados sin usar, no se obtendrán errores de compilación debido a que faltarán archivos de encabezado incluidos indirectamente por un archivo de encabezado que quitó.

Una manera de hacerlo es establecer la opción de limpieza de directivas include para Agregar nivel de sugerencias de inclusiones perdidas a Sugerencia (Herramientas>Opciones>Editor de texto>C/C++>Limpieza de código). Establezca también Quitar nivel de sugerencias de inclusiones sin usar en Sugerencia. Después:

  1. En la lista de errores, asegúrese de que el filtro esté establecido en Compilar + IntelliSense.
  2. Busque instancias de "Contenido de #include x se usa en este archivo y se incluye transitivamente".
  3. Mantenga el cursor sobre una línea con la sugerencia. En la lista desplegable de la bombilla, seleccione Agregar todas las inclusiones usadas transitivamente.
  4. Repita estos pasos en el proyecto hasta que se aborden todas las sugerencias relacionadas con las inclusiones transitivas.
  5. Quitar inclusiones sin usar: en la lista de errores, busque una instancia donde diga "#include x no se usa en este archivo".
  6. Mantenga el cursor sobre el encabezado sin usar. En la lista desplegable de la bombilla, seleccione Quitar todas las inclusiones sin usar.
  7. Repita estos pasos en el proyecto hasta que se resuelvan todas las sugerencias de la limpieza de directivas include.

En esta breve introducción, ha visto cómo la limpieza de directivas include puede ayudarle a quitar encabezados sin usar y agregar encabezados que se incluyeron indirectamente. Esto le ayudará a mantener el código limpio, a compilar potencialmente más rápido y a reducir la fragilidad del código.

Consulte también

Configuración de la limpieza de directivas include de C/C++ en Visual Studio
Mensajes de limpieza de directivas include