ヘッダーがCPPファイルに明示的に含まれるようにする


9

#includeHPPファイルを介して既に何がインクルードされているかに関係なく、CPPファイルで使用されるすべてのタイプのヘッダーには、一般的には良い習慣だと思います。#include <string>たとえば、CPPでスキップした場合でもコンパイルできたとしても、HPPとCPPの両方で使用する可能性があります。これにより、HPPがフォワード宣言を使用したかどうかを心配する必要がなくなります。

この#includeコーディングスタイルを適用できるツールはありますか?このコーディングスタイルを適用する必要がありますか?

プリプロセッサー/コンパイラーは#includeHPPからのものかCPPからのものかを気にしないので、このスタイルに従うのを忘れてもフィードバックは得られません。

回答:


7

これは、「Shall」ではなく、「すべき」コーディング標準の1つです。その理由は、それを強制するためにC ++パーサーを作成する必要があるからです。

ヘッダーファイルの非常に一般的なルールは、ヘッダーファイルが独立している必要があることです。ヘッダーファイルでは、問題のヘッダーをインクルードする前に、他の一部のヘッダーファイルを#includeする必要はありません。これはテスト可能な要件です。いくつかのランダムなヘッダーfoo.hhを指定すると、次のコードがコンパイルされて実行されます。

#include "foo.hh"
int main () {
   return 0;
}

このルールは、一部のヘッダーでの他のクラスの使用に関して影響を及ぼします。これらの他のクラスを前方宣言することにより、これらの結果を回避できる場合があります。これは、多くの標準ライブラリクラスでは不可能です。std::stringまたはなどのテンプレートのインスタンス化を転送宣言する方法はありませんstd::vector<SomeType>。あなたはに持っている#includeタイプの使用のみが関数の引数としてであっても、ヘッダーのものSTLヘッダ。

もう1つの問題は、偶発的にドラッグしたものです。例:次のことを考慮してください。

ファイルfoo.cc:

#include "foo.hh"
#include "bar.hh"

void Foo::Foo () : bar() { /* body elided */ }

void Foo::do_something (int item) {
   ...
   bar.add_item (item);
   ...
}

ここではbarクラスであるFoo型であるデータメンバーBar。あなたはここで正しいことを行い、それがclassを定義するヘッダーに含まれていなければならなかったとしても#included bar.hhを持っていFooます。ただし、Bar::Bar()およびで使用されるものは含まれていませんBar::add_item(int)。これらの呼び出しにより、追加の外部参照が発生する可能性がある多くの場合があります。

foo.oなどのツールで分析すると、nmの関数foo.ccが、適切な処理を行っていないあらゆる種類の機能を呼び出しているように見えます#include。では#include、これらの偶発的な外部参照のディレクティブを追加する必要がありますfoo.ccか?答えは絶対にありません。問題は、偶発的に呼び出される関数と直接呼び出される関数を区別するのが非常に難しいことです。


2

このコーディングスタイルを適用する必要がありますか?

おそらく違います。私のルールはこれです:ヘッダーファイルのインクルードは順序に依存することはできません。

これは、xcに含まれる最初のファイルがxhであるという単純なルールで非常に簡単に確認できます。


1
これについて詳しく説明できますか?それが実際に順序の独立性を検証する方法を私は見ることができません。
detly

1
順序の独立性を実際に保証するものではありません。これは#include "x.h"、先行を必要とせずに動作することを保証するだけ#includeです。虐待しないのであればそれで十分です#define
ケビンクライン2013年

1
ああなるほど。それでも良い考えです。
2013年

2

特定のヘッダーファイルが独立している必要があるというルールを適用する必要がある場合は、既存のツールを使用できます。各ヘッダーファイルを個別にコンパイルするが、オブジェクトファイルを生成しない基本的なmakefileを作成します。ヘッダーファイルをコンパイルするモード(CまたはC ++モード)を指定し、それが独自に立つことができることを確認できます。出力に誤検知が含まれておらず、必要なすべての依存関係が宣言されており、出力が正確であると合理的に想定できます。

IDEを使用している場合でも、(IDEによっては)makefileがなくてもこれを実現できる場合があります。追加のプロジェクトを作成し、確認するヘッダーファイルを追加し、設定を変更してCまたはC ++ファイルとしてコンパイルします。たとえばMSVCでは、「構成プロパティ->全般」の「アイテムタイプ」設定を変更します。


1

私はそのようなツールは存在しないと思いますが、他の答えが私に反証してくれれば幸いです。

このようなツールを作成する際の問題は、誤った結果を非常に簡単に報告することです。そのため、このようなツールの正味の利点はゼロに近いと推定しています。

このようなツールが機能する唯一の方法は、そのシンボルテーブルを、処理したヘッダーファイルの内容だけにリセットできる場合ですが、ライブラリの外部APIを形成するヘッダーが実際の宣言を委任するという問題が発生します。内部ヘッダー。
たとえば<string>、GCCのlibc ++実装では何も宣言されていませんが、実際の宣言を含む内部ヘッダーの束が含まれているだけです。ツールがそのシンボルテーブルを<string>それ自体で宣言されたものだけにリセットした場合、それは何もありません。
あなたは間のツールの分化を持つことができ#include ""、および#include <>、それ外部ライブラリが使用する場合は、あなたを助けていない#include ""APIでその内部ヘッダをインクルードします。


1

#Pragma onceこれを達成できませんか?直接または連鎖インクルードを介して、必要なだけ何回でもインクルードできます。#Pragma onceそれぞれの隣にある限り、ヘッダーは1回だけインクルードされます。

それを実施することに関しては、おそらく、それがコンパイルされることを保証するために、ダミーのメイン関数を使用して各ヘッダーを単独で含むビルドシステムを作成することができます。#ifdefチェーンには、そのテスト方法で最良の結果を得るために含まれています。


1

CPPファイルには常にヘッダーファイルを含めます。これにより、コンパイル時間が大幅に短縮されるだけでなく、プリコンパイル済みヘッダーを使用する場合のトラブルも大幅に軽減されます。私の経験では、フォワード宣言のトラブルをすることさえ練習中に価値があります。必要なときだけルールを破る。


これが「コンパイル時間を大幅に短縮する」方法を説明できますか?
Mawgはモニカを2016

1
これにより、各コンパイルユニット(CPPファイル)は、コンパイル時に最小限のインクルードファイルのみを取得します。それ以外の場合、インクルードをHファイルに入れると、誤った依存チェーンがすばやく形成され、コンパイルごとにすべてのインクルードがプルされます。
Gvozden、2016年

インクルードガードを使用すると、「重要」に質問する可能性がありますが、ディスクアクセス(それらのインクルードガードを発見するための順序で)が「遅い」ため、要点を譲ります。明確にしていただきありがとうございます
-Mawgはモニカを2016

0

この条約には長所と短所の両方があると思います。一方で、.cppファイルに何が含まれているかを正確に把握しておくと便利です。一方、インクルードのリストはとんでもないサイズに簡単に大きくなる可能性があります。

この規則を奨励する1つの方法は、独自のヘッダーには何も含めず、.cppファイルにのみ含めることです。依存する他のすべてのヘッダーを明示的に含めない限り、ヘッダーを使用する.cppファイルはコンパイルされません。

おそらく、ここである程度の妥協が必要です。たとえば、独自のヘッダー内に標準ライブラリヘッダーを含めてもかまいませんが、それ以上はできません。


3
ヘッダーに含まれていないインクルードをそのままにしておくと、インクルードの順序が重要になります...そして、私は絶対にそれを避けたいです。
M.ダドリー2013年

1
-1:依存関係の悪夢を作成します。xhの機能強化には、xhを含む
すべての

1
@M。ダドリー、私が言ったように、長所と短所があります。
ディマ2013年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.