65

小さな関数がたくさんあるクラスがあります。小さな関数とは、処理を行わずにリテラル値を返すだけの関数を意味します。何かのようなもの:

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

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

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

6 に答える 6

71

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

headera.h :

inline string method() {
    return something;
}

メンバー関数は、クラス内で定義されている場合、暗黙的なインラインです。それらについても同じことが当てはまります。問題なくヘッダーに配置できる場合は、実際にそうすることができます。

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

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

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

于 2009-01-17T14:44:05.473 に答える
12

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

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

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

覚えておくべきもう1つのことは、DLL /共有ライブラリでクラスをエクスポートする場合(私見では良い考えではありませんが、人々はとにかくそれを行います)、インライン関数には本当に注意する必要があるということです。DLL をビルドしたコンパイラが関数をインライン化する必要があると判断した場合、いくつかの問題が発生する可能性があります。

  1. DLL を使用してプログラムをビルドするコンパイラは、関数をインライン化しないことを決定する場合があるため、存在しない関数へのシンボル参照が生成され、DLL は読み込まれません。
  2. DLL を更新してインライン化された関数を変更すると、関数がクライアント コードにインライン化されるため、クライアント プログラムはその関数の古いバージョンを引き続き使用します。
于 2009-01-17T15:18:42.003 に答える
5

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

コンパイラについてのあなたの言うことも真実です.ヘッダーファイルまたはファイルのコードの間に、インライン化以外のコンパイラの違いはありません.cpp

于 2009-01-17T14:41:15.387 に答える
2

ケースに適用されるコーディング標準によって異なりますが、次のとおりです。

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

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

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

したがって、短い答えは次のとおりです。

-- ヘッダーで関数を宣言することは、速度には適しています (ただし、スペースには適していません) --

于 2009-01-17T14:49:04.933 に答える
2
  1. 関数がそれほど単純な場合は、それらをインラインにします。いずれにせよ、それらをヘッダー ファイルに貼り付ける必要があります。それ以外は、慣習はまさにそれです-慣習。

  2. はい、コンパイラは #include ステートメントに遭遇したヘッダー ファイルを展開します。

于 2009-01-17T14:42:24.337 に答える
1

そうした場合、C++ は文句を言いませんが、一般的に言えば、文句を言うべきではありません。

ファイルを#includeすると、インクルードされたファイルのコンテンツ全体がインクルードのポイントに挿入されます。これは、ヘッダーに配置した定義が、そのヘッダーを含むすべてのファイルにコピーされることを意味します。

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

変更される可能性が低い単純な関数 (たとえば、関数定義が 1 行の場合) に対して例外が作成されることがあります。

出典: http://archive.li/ACYlo (learncpp.com の第 1.9 章の前のバージョン)

于 2016-12-05T05:57:01.920 に答える