ホームページ  >  記事  >  バックエンド開発  >  C++ 関数のインライン化

C++ 関数のインライン化

黄舟
黄舟オリジナル
2017-02-06 13:38:521076ブラウズ

1. マクロコードをインライン化に置き換える


C++言語は関数の実行効率(速度)を向上させることを目的とした関数のインライン化をサポートしています。

C プログラムでは、マクロ コードを使用して実行効率を向上させることができます。マクロ コード自体は関数ではありませんが、関数のように動作します。 プリプロセッサはマクロ コードをコピーすることで関数呼び出しを置き換え、パラメータをスタックにプッシュし、アセンブリ言語で CALL 呼び出しを生成し、パラメータを返し、リターンを実行する必要がなくなるため、速度が向上します。マクロ コードを使用する最大の欠点は、マクロ コードをコピーするときに、プリプロセッサによって予期しない副作用が発生することが多いことです。


たとえば、

#define MAX(a, b)         (a) > (b) ? (a) : (b)

ステートメント

result = MAX(i, j) + 2 ;

は、プリプロセッサによって

result = (i) > (j) ? (i) : (j) + 2 ;

として解釈されます。 演算子 '+' は演算子 ':' よりも優先順位が高いため、上記のステートメントは予想通り

result = ( (i) > (j) ? (i) : (j) ) + 2 ;

マクロコードを

#define MAX(a, b) ( (a) > (b) ? (a) : (b) )

に書き換えると優先度によるエラーを解決できます。しかし、変更されたマクロ コードを使用しても、確実に実行できるわけではありません。たとえば、ステートメント

result = MAX(i++, j);

はプリプロセッサによって

result = (i++) > (j) ? (i++) : (j);

として解釈されます。C++ の場合、マクロ コードを使用することにはもう 1 つの欠点があります。それは、マクロ コードのプライベート データ メンバーを操作できないことです。クラス、つまりマクロ コードは基本的にパブリックまたはグローバル操作用です。


C++ で「関数のインライン化」がどのように機能するかを見てみましょう。インライン関数の場合、コンパイラは関数の宣言 (名前、パラメーターの型、戻り値の型を含む) をシンボル テーブルに配置します。コンパイラがインライン関数にエラーを検出しなかった場合、その関数のコードもシンボル テーブルに配置されます。インライン関数を呼び出すとき、コンパイラは最初に呼び出しが正しいかどうかをチェックします (型安全性チェックを実行するか、自動型変換を実行します。もちろんすべての関数で同じです)。正しい場合は、インライン関数のコードが関数呼び出しを直接置き換えることになり、関数呼び出しのオーバーヘッドが排除されます。プリプロセッサは型安全性チェックや自動型変換を実行できないため、このプロセスは前処理とは大きく異なります。インライン関数がメンバー関数である場合、オブジェクト (this) のアドレスは適切な場所に配置されますが、これはプリプロセッサでは実行できません。


C++言語の関数インライン化機構は、マクロコードの効率化だけでなく、セキュリティ性も高め、クラスのデータメンバーを自由に操作することができます。したがって、C++ プログラムでは、すべてのマクロ コードをインライン関数に置き換える必要があります。おそらく、「assert」は唯一の例外です。 assert は、デバッグ バージョンでのみ機能するマクロで、「起こるべきではない」状況をチェックするために使用されます。プログラムのデバッグ バージョンとリリース バージョンの間に違いが生じないようにするために、assert には副作用があってはなりません。 Assert が関数の場合、関数呼び出しによってメモリとコードが変更されるため、Debug バージョンと Release バージョンの間に違いが生じます。 したがって、assert は関数ではなくマクロです。


2. インライン関数のプログラミングスタイル


関数をインライン化するには、キーワード inline を関数定義本体と一緒に配置する必要があります。単に関数宣言の前に inline を配置しても効果はありません。次のスタイルの関数 Foo はインライン関数になることはできません:

inline void Foo(int x, int y);   // inline 仅与函数声明放在一起,不起任何作用  
void Foo(int x, int y)  
{  
…  
}

そして、次のスタイルの関数 Foo はインライン関数になります:

void Foo(int x, int y);    
inline void Foo(int x, int y) // inline 与函数定义体放在一起  
{  
…  
}


したがって、inline は「実装のためのキーワード」であり、「キーワード」ではありません。宣言のため」。 一般に、ユーザーは関数の宣言を読むことはできますが、関数の定義を見ることはできません。多くの教科書では inline 関数の宣言や定義本体の前に inline キーワードが追加されていますが、関数の宣言中に inline は登場すべきではないと思います。この詳細は関数の機能には影響しませんが、高品質な C++/C プログラミング スタイルの基本原則を反映しています。つまり、宣言と定義を混同してはならず、ユーザーは関数に必要があるかどうかを知る必要はなく、また知るべきではありません。インライン化する。


クラス宣言で定義したメンバ関数は

class A  
{  
public:  
    void Foo(int x, int y) { … }   // 自动地成为内联函数  
}


のような自動的にインライン関数になります クラス宣言の中にメンバ関数の定義本体を置くと記述が便利になりますが、それは良いことではありません。上の例は次のように変更する必要があります:

// 头文件  
class A  
{  
public:  
    void Foo(int x, int y);  
}  
// 定义文件  
inline void A::Foo(int x, int y)  
{  
…  
}

3. インライン化は注意して使用してください


すべての関数をインライン関数として定義してはいかがでしょうか。


すべての関数がインライン関数である場合、キーワード「inline」はまだ必要ですか?


インライン化はコードの拡張(重複)を犠牲にして、関数呼び出しのオーバーヘッドのみを節約するため、関数の実行効率が向上します。関数本体内のコードの実行時間が関数呼び出しのオーバーヘッドよりも長い場合、効率の向上は非常に小さくなります。一方、インライン関数呼び出しごとにコードの重複が必要となるため、プログラムの合計コード サイズが増加し、より多くのメモリ領域を消費します。次の状況ではインライン化を使用することは適切ではありません:


(1) 関数本体のコードが比較的長い場合、インライン化を使用するとメモリ消費コストが高くなります。


(2) 関数本体でループが発生した場合、関数本体内のコードの実行時間は関数呼び出しのコストよりも大きくなります。


クラスのコンストラクターとデストラクターは、インラインを使用する方が効率的であると誤解されやすいです。コンストラクターとデストラクターには注意してください。関数は、基本クラスまたはメンバー オブジェクトのコンストラクターとデストラクターを「秘密裏に」実行するなど、一部の動作を隠している場合があります。 したがって、クラス宣言にコンストラクターとデストラクターの定義を単に入れないでください。

上記は C++ 関数のインライン化の内容です。さらに関連する内容については、PHP 中国語 Web サイト (www.php.cn) に注目してください。


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。