2013-04-07 1 views
9

私の関数をインラインにするかどうかにかかわらず、コンパイラはすべてこのキーワードを完全に使用することを止めることができます(それはとにかくすべてをインラインで実行すると仮定して)。"インライン"の使用を中止できますか?

答えて

12

inlineの使用を中止することができます。

inlineは、基本的には、ODR (One Definition Rule)を適用しない場合にのみ有効です。要するに、あなたはinlineとしての機能をマークすることができますし、この不満リンカずに、複数の翻訳単位で輸入された1つのヘッダファイルに直接彼らの定義を提供:

foo.hpp

inline int foo() { return 42; } 

foo.cpp

#include "foo.hpp" // <== THE LINKER WOULD COMPLAIN IF foo() WERE NOT inline, 
        //  because its definition is imported also in main.cpp 
void bar() 
{ 
    int x = foo(); 
} 

main.cppに

#include "foo.hpp" // <== THE LINKER WOULD COMPLAIN IF foo() WERE NOT inline, 
        //  because its definition is imported also in foo.cpp 
int main() 
{ 
    std::cout << foo(); 
} 

(、再び、コンパイラがインライン展開を実行することを保証するものではありません)inlineキーワードの存在は、リンカがそれらの定義をマージするようになります。もちろん

、このマージ操作は意味のあるものにするためには、いくつかの異なる翻訳単位の一部になってしまうinlineとしてマークされた機能のすべての定義が同じでなければなりません。これが当てはまらない場合は、プログラムに未定義の動作があり、診断は不要です。つまり、コンパイラ/リンカはこの不一致を検出する必要はなく、何かが間違っていると伝えます。

すべてのプログラムがその中に をODR-使用されているすべての非インライン関数や変数の正確に一つの定義が含まれていなければならない。実際にはC++ 11標準のパラグラフ3.2/4パー

プログラム;診断不要。定義はプログラム内で明示的に現れることができ、標準またはユーザ定義のライブラリに があるか、または必要に応じて暗黙的に定義されます(12.1,12.4および 12.8を参照)。インライン関数は、それがodr使用されるすべての翻訳単位で定義されなければならない。あなたは文字通りinlineとしてマークされた同等の機能を有することができることを

通知は、異なる翻訳単位で2回を定義し、それは限り、それらの定義が同一であるとして罰金です:

foo.cpp

inline int foo() // Has the same body in main.cpp, no problem! 
{ 
    return 42; 
} 

メイン。

inline int foo() // Has the same body in foo.cpp, no problem! 
{ 
    return 42; 
} 

int main() 
{ 
    std::cout << foo(); 
} 

CPPはしかし、二つの定義が異なる場合は、次の例のように、あなたのコードでUBを注入します:

foo.cpp

inline int foo() 
{ 
    return 42; // <== WATCH OUT! Different body in main.cpp 
} 

メイン。 cpp

inline int foo() 
{ 
    return -42; // <== WATCH OUT! Different body in foo.cpp 
} 

int main() 
{ 
    std::cout << foo(); 
} 

これは、一般的に#include dヘッダーファイルに定義を直接入力すると、関数をinlineとマークする理由です。

また、クラス定義で定義が直接インライン化されているクラスメンバ関数は、自動的にinlineとマークされています。

+0

'' inline'を使用しない場合でも、暗黙的に使用することができます: 'struct Foo {int x; foo():x(0){}}; 'は1つの.cppファイル内にあり、' struct Foo {double d;別の.cppファイルに 'Foo():d(0){}};'を入れ、 'Foo :: Foo'という2つの' inline'コンストラクタを暗黙的に作成しました。 – Yakk

+1

@ヤク:次に、あなたのプログラムは、 'Foo'が匿名の名前空間で宣言されていない限り、未定義の動作をします。 @MatthieuM。 –

+0

うん、私はそれが生産コードで起こっているのを見た。基本的には、「インライン」を使用しなくても、それに噛まれることができるので、インラインが本当に何であるかを理解する必要があります。 – Yakk

5

inlineの用途に応じて異なります。

コモン(MIS) 概念:
inlineだけコンパイラは、またはそれに従わなくてもよい提案です。とにかに、良いコンパイラは何をする必要があるのでしょう。

一方、真実:

inline通常コールの時点で、関数本体のインライン置換は、通常の関数呼び出し機構に好ましいことであること実装に示します。実装時に、このインライン置換をコール時に実行する必要はありません。 inlineの置換が省略されても、inlineの他の規則(特にw.r.t One Definition Rule)に従います。使用方法のあなたの目的は、最適化ある場合

だから答えは:

YES、あなたがinlineの使用を停止することができます。現代のコンパイラのほとんどはあなたのためにそれをかなりうまく行います

しかしinlineの使用方法のあなたの目的は、あなたが答える一つの定義ルールを乗り越えるとODRを壊すことなく、ヘッダーファイル内の関数本体を定義することができるようになる場合は、次のとおりです。

NO ODRをバイパスできるように、関数を明示的にinlineとマークする必要があります。

注:クラス本体内に定義されたメンバ関数は、暗黙的にinlineですが、無料の機能には適用されません同じ。

関連する問題