web-dev-qa-db-ja.com

C ++のヘッダーファイルに関数定義を書く

私は多くの小さな機能を持つクラスを持っています。小さな関数とは、処理を行わず、リテラル値を返すだけの関数を意味します。何かのようなもの:

string Foo::method() const{
    return "A";
}

ヘッダーファイル「Foo.h」とソースファイル「Foo.cpp」を作成しました。ただし、関数は非常に小さいため、ヘッダーファイル自体に配置することを考えています。次の質問があります。

  1. これらの関数定義をヘッダーファイルに入れた場合、パフォーマンスやその他の問題はありますか?このような多くの機能があります。
  2. 私の理解では、コンパイルが完了すると、コンパイラはヘッダーファイルを展開し、それが含まれている場所に配置します。あれは正しいですか?
61
Navaneeth K N

関数が小さい場合(頻繁に変更する可能性が低い)、および他の無数のヘッダーを含めることなく関数をヘッダーに配置できる場合(関数はそれらに依存しているため)、そうすることは完全に有効です。それらをexternインラインで宣言する場合、コンパイラーはすべてのコンパイル単位に同じアドレスを与える必要があります。

headera.h

inline string method() {
    return something;
}

メンバー関数は、クラス内で定義されていれば暗黙のインラインです。同じことが当てはまります。面倒なことなくヘッダーに入れることができれば、本当にできます。

関数のコードはヘッダーに配置されて表示されるため、コンパイラーはそれらの呼び出しをインライン化できます。つまり、関数のコードを呼び出しサイトに直接配置できます(インラインをその前に置くためではなく、ただし、コンパイラがその方法を決定するためです。インラインのみを配置することは、コンパイラに関するヒントです。コンパイラーは、引数が関数のローカル変数と一致する場所と、引数が相互にエイリアスしない場所を認識するようになったため、パフォーマンスが向上する可能性があります。

私の理解では、コンパイルが完了すると、コンパイラはヘッダーファイルを展開し、それが含まれている場所に配置します。あれは正しいですか?

はい、それは正しいです。関数は、ヘッダーを含めるすべての場所で定義されます。コンパイラは、他のインスタンスを削除することにより、結果のプログラムにそのインスタンスを1つだけ配置することに注意します。

コンパイラとその設定に応じて、次のいずれかを実行できます。

  • Inlineキーワードを無視し(コマンドではなくコンパイラーへのヒントにすぎません)、スタンドアロン関数を生成します。関数がコンパイラ依存の複雑度のしきい値を超えた場合、これを行うことがあります。例えばネストされたループが多すぎます。
  • スタンドアロン機能がインライン展開の良い候補であると判断する場合があります。

多くの場合、コンパイラーは、関数をインライン化する必要があるかどうかを判断するのに、はるかに優れた立場にあるため、関数を推測することには意味がありません。クラスに多くの小さな関数があるときに暗黙的なインライン化を使用するのが好きなのは、クラス内で実装を行うのが便利だからです。これは、より大きな関数ではあまりうまく機能しません。

もう1つ覚えておく必要があるのは、DLL /共有ライブラリのクラスをエクスポートする場合(良いアイデアではありませんが、とにかく人々がそれを行います)、インライン関数には本当に注意する必要があるということです。 DLL=を作成したコンパイラが関数をインライン化する必要があると判断した場合、潜在的な問題がいくつかあります。

  1. DLLを使用してプログラムを構築するコンパイラは、関数をインライン化しないことを決定する可能性があるため、存在しない関数へのシンボル参照を生成し、DLL =ロードされません。
  2. DLLを更新し、インライン関数を変更した場合、関数はクライアントコードにインライン化されたため、クライアントプログラムはその関数の古いバージョンを引き続き使用します。
12
Ferruccio

ヘッダーファイルでの実装が暗黙的にインライン化されるため、パフォーマンスが向上します。あなたの機能が小さいと述べたように、インライン操作はあなたにとって私にとって非常に有益です。

コンパイラについてあなたが言うことも真実です。インラインファイル以外のコンパイラでは、ヘッダーファイル内のコードと.cppファイル。

4
Qubeuc
  1. 関数がこれほど単純な場合は、関数をインラインにします。とにかくヘッダーファイルに挿入する必要があります。それ以外は、規則はそれだけです-規則。

  2. はい、コンパイラは#include文が検出された場所でヘッダーファイルを展開します。

2
sykora

それはあなたのケースに適用されるコーディング標準に依存しますが:

ループなどのない小さな関数は、パフォーマンスを向上させるためにインライン化する必要があります(ただし、コードが若干大きくなります-制約のあるアプリケーションや組み込みアプリケーションでは重要です)。

ヘッダーに関数の本体がある場合は、デフォルトでinline(d)になります(速度に関しては良いことです)。

コンパイラによってオブジェクトファイルが作成される前に、プリプロセッサが呼び出され(gccの-Eオプション)、結果がコンパイラから送信され、コードからオブジェクトが作成されます。

短い答えは次のとおりです。

-ヘッダーで関数を宣言すると速度が向上します(ただし、スペースは低下しません)-

2
INS

C++で文句を言うことはありませんが、一般的に言って、すべきではありません。

ファイルをインクルードすると、インクルードされたファイルのコンテンツ全体がインクルードの時点で挿入されます。つまり、ヘッダーに定義を定義すると、そのヘッダーを含むすべてのファイルにコピーされます。

小さなプロジェクトの場合、これは大きな問題にはなりそうにありません。ただし、大規模なプロジェクトの場合、これによりコンパイルに時間がかかり(検出されるたびに同じコードが再コンパイルされるため)、実行可能ファイルのサイズが大幅に増大する可能性があります。コードファイルの定義を変更する場合、その.cppファイルのみを再コンパイルする必要があります。ヘッダーファイルの定義を変更した場合、ヘッダーを含むすべてのコードファイルを再コンパイルする必要があります。 1つの小さな変更により、プロジェクト全体を再コンパイルする必要がある場合があります。

変更されそうにない些細な関数に対して例外が作成される場合があります(関数定義が1行の場合など)。

ソース: http://archive.li/ACYlo (learncpp.comの1.9章の以前のバージョン)

1
Pushpak Sharma

インライン関数を使用する必要があります。これを読んでください インライン関数 理解を深め、トレードオフに関係します。

0
Naveen