Rileva le catene di inclusione di intestazione e le dipendenze in C ++

1

File Top.h

#include <string>
...some code...

File Bottom.h:

#include "Top.h"

void someFunction() {
  string s = new String();
  ...
}

Il Bottom.h non contiene un inclusivo per l'intestazione della stringa, ma il codice funzionerà perché è implicitamente incluso da Top.h

Ora, se Top.h cambia per qualsiasi motivo per non includere più string, Bottom.h si interromperà.

So che è buona norma avere i file .h "include independent", il che significa che ognuno di essi include esplicitamente tutte le intestazioni che usa. Tuttavia, il mantenimento di tale pratica è un compito mentale aggiuntivo che devo fare, che è soggetto a errori poiché lo sto facendo manualmente.

C'è un modo per far controllare l'IDE o il compilatore? Esistono analizzatori di codici statici che avvertono l'utente che stanno utilizzando un componente che non è esplicitamente incluso nel file in cui è utilizzato? C'è un flag del compilatore che verifica questo? Mi sono occupato di questo problema e non sono riuscito a trovare nulla di simile, ma non sembra difficile da implementare e sembra qualcosa che possa garantire la stabilità del codice. Detto questo, c'è una ragione per cui quello che sto suggerendo sarebbe una cattiva idea o non funziona in alcuni casi? Se sì, quale?

Ha senso?

EDIT dopo aver letto alcune risposte:

Potrebbe essere possibile rendere linker / compilatore semi-processare ogni file semi-separatamente?

Prenderebbe ogni file e guarderà tutte le intestazioni che include. Quindi passa attraverso quei file, ma non li compila, guarda solo quali simboli sono definiti lì, escludendo le proprie intestazioni . Quindi passa attraverso il file che abbiamo iniziato e vediamo se utilizza i simboli che non ha incontrato nel passaggio precedente. Se lo fa, significa che il simbolo non è affatto incluso o è stato incluso implicitamente attraverso l'intestazione di uno degli include.

Non risolverebbe il problema, o ci sono alcune caratteristiche del C ++ che non funzionerebbero con questo?

    
posta Karlovsky120 04.10.2018 - 11:22
fonte

3 risposte

2

Questo è un problema comune ma irrisolvibile con C ++. Un'intestazione fornisce alcune dichiarazioni. Il modo in cui l'intestazione fornisce queste dichiarazioni è un dettaglio di implementazione ed è completamente valido se l'intestazione fornisce una dichiarazione includendo un'altra intestazione. Questo è abbastanza comune nelle librerie di sola intestazione, o grandi librerie come implementazioni di librerie standard. Pertanto è impossibile in generale per stabilire se una dipendenza indiretta è corretta o meno.

Per ridurre al minimo le dipendenze di intestazione transitiva indesiderate, sono disponibili varie strategie.

Come utente di un'intestazione:

  • Leggi la documentazione per capire quali dichiarazioni dovrebbero essere disponibili da quale intestazione. Non c'è davvero nessuna buona soluzione per questo. Non sovraccaricare il completamento automatico per vedere se è disponibile una dichiarazione.

    I Linters potrebbero essere a conoscenza delle intestazioni delle librerie standard.

  • Ordina le intestazioni che includi per livello: prima il tuo, poi eventuali altre librerie e infine le intestazioni delle librerie standard. Quando tutti lo fanno, diventa più probabile trovare le dipendenze mancanti in un'intestazione inclusa. Non aiuta se un'intestazione include altre intestazioni non necessarie.

Come autore di un file di intestazione:

  • Scrivi una documentazione chiara su quale funzionalità dovrebbe essere fornita da quali intestazioni. Se si sta scrivendo una libreria, un'intestazione pubblica per l'intera libreria potrebbe almeno evitare problemi con le dipendenze interne. Per una libreria di classi, può essere utile anche una progettazione a classe singola per intestazione, in cui l'intestazione può essere denominata dopo la classe.

  • Riduci a icona quali intestazioni includere. Preferisci le dichiarazioni in avanti oltre a includere un'intestazione. Non devi inoltrare parti della libreria standard, ma la libreria standard C ++ fornisce alcune dichiarazioni di avanzamento in <iosfwd> .

  • Include solo intestazioni che fanno parte della tua API pubblica, ad esempio come tipi di argomenti o tipi di membri della classe. Se si include un'intestazione per accedere a una particolare funzione, è preferibile includerla in un file .cpp. Puoi nascondere i membri della classe dalla tua interfaccia pubblica con il modello pImpl, con una leggera perdita di efficienza.

    Sfortunatamente, queste tecniche sono generalmente inapplicabili per le librerie di sola intestazione e per i modelli.

  • Se possibile, prova con diverse implementazioni di libreria. Diverse implementazioni dovrebbero essere compatibili se usate correttamente, ma potrebbero strutturare le loro intestazioni in modo diverso - probabilmente portando a dichiarazioni "mancanti".

I moduli C ++ dovrebbero limitare l'intestazione transitive e le anteprime sono disponibili in alcuni compilatori. I moduli renderanno più chiaro dichiarare quali nomi vengono esportati da un'intestazione / modulo. Ma fino a quando non saranno ampiamente disponibili (forse già con C ++ 20), dobbiamo fare affidamento sulla documentazione dell'intestazione.

    
risposta data 04.10.2018 - 14:11
fonte
0

Una regola che dovrebbe seguire in linguaggi come C, C ++, Objective-C è che ogni singolo file di intestazione si compila da solo. Questo è realizzato qui (quindi qualcuno che include bottom.h non ha bisogno di ricordare di includere top.h una stringa).

In pratica, il caso di rimuovere una intestazione come stringa da top.h è raro, il compilatore ti dice, aggiungi la stringa a fondo.h in cinque secondi, tutto va bene e non ti preoccupare. Spetta naturalmente allo sviluppatore cambiare top.h per sistemare tutto ciò che si rompe.

    
risposta data 04.10.2018 - 15:10
fonte
0

Utilizza i test delle unità.

Disponi il codice di prova dell'unità in modo che ogni unità di test / suite venga eseguita in un'unità di traduzione separata. Ciò significa che ogni intestazione viene tirata e sperimentata in uno o più programmi alternativi che avranno ecosistemi di namespace diversi, esponendo così ipotesi sui simboli che sono stati definiti.

    
risposta data 04.10.2018 - 15:38
fonte

Leggi altre domande sui tag