web-dev-qa-db-ja.com

静的インライン関数を決して使用すべきではありませんか?

inlineキーワードの使用には2つの意味があります(§7.1.3/4):

  1. It hintsコンパイラは、通常の関数呼び出しメカニズムよりも、呼び出しポイントでの関数本体の置換が望ましいことを示しています。
  2. インライン置換が省略された場合でも、インラインのその他のルール(特にw.r.t One Definition Rule)に従います。

通常、メインストリームコンパイラは必要に応じて呼び出しポイントで関数本体を置換するため、関数inlineを単に#1は実際には必要ありません。

さらにw.r.t #2、関数をstatic inline 関数、

関数のstaticキーワードは、inline関数に内部リンケージを強制します(インライン関数には外部リンケージがあります)このような関数の各インスタンスは、個別のインスタンスとして扱われますfunction(各関数のアドレスが異なる)、これらの関数の各インスタンスには、静的ローカル変数と文字列リテラルの独自のコピーがあります(インライン関数にはこれらのコピーが1つしかありません

したがって、このような関数は他のstatic関数と同様に機能し、キーワードinlineはもはや重要ではなくなり、冗長になります。

そのため、関数staticinlineの両方を実際にマークすることは、まったく役に立ちません。 static最も優先されない)またはinline最も優先される)、
それで、関数でstaticinlineを一緒に使用しています実際には役に立たない?

58
Alok Save

あなたの分析は正しいが、必ずしも役に立たないという意味ではない。ほとんどのコンパイラが関数を自動的にインライン化する場合でも(理由#1)、意図を記述するためだけにinlineを宣言するのが最善です。

inlinestatic関数との相互作用を無視することは控えめに使用する必要があります。名前空間スコープのstatic修飾子は、以前は名前のない名前空間を優先するために廃止されました(C++ 03§D.2)。 C++ 11の非推奨から削除されたことを思い出せない不明瞭な理由により、ほとんど必要ないはずです。

したがって、関数を静的とインラインの両方に実際にマークすることは、まったく役に立ちません。静的(最も優先されない)またはインライン(最も優先される)である必要があります。

好みの概念はありません。 staticは、同じシグネチャを持つ異なる関数が異なる.cppファイル(翻訳単位)。 inlinestaticなしで使用すると、異なる翻訳単位で同じ関数を同じ定義で定義してもかまいません。

isが望ましいのは、staticの代わりに名前のない名前空間を使用することです:

namespace {
    inline void better(); // give the function a unique name
}

static inline void worse(); // kludge the linker to allowing duplicates
48
Potatoswatter

静的およびインラインは直交(独立)です。静的とは、関数が翻訳単位の外に表示されるべきではないことを意味します。インラインは、プログラマがこの関数をインライン化することを望むコンパイラへのヒントです。これら2つは関連していません。

static inlineを使用することは、インライン化された関数が翻訳単位の外部で使用されない場合に意味があります。これを使用することにより、同じ名前の別の翻訳単位で別のインライン関数に名前を付けることで、ODRルールの偶発的な違反の状況を防ぐことができます。

例:

source1.cpp:

inline int Foo()
{
  return 1;
}

int Bar1()
{
  return Foo();
}

source2.cpp:

inline int Foo()
{
  return 2;
}

int Bar2()
{
  return Foo();
}

Fooでstaticを使用しない(またはほとんどのC++プログラマーが好む匿名名前空間を使用しない)場合、この例はODRに違反し、結果は未定義です。 Visual Studioでテストできます。Bar1/ Bar2の結果はコンパイラの設定に依存します-デバッグ構成では、Bar1とBar2の両方が同じ値を返します(インライン展開は使用されず、1つの実装はリンカによってランダムに選択されます)。意図した値を返します。

23
Suma

私はこれについて完全に正しいわけではないかもしれませんが、関数の宣言を知っている限り_static inlineは、コンパイラがマシンコードを生成する(または許可する)唯一の方法であり、関数はコンパイルされたコードで実際に定義されておらず、宣言された関数を命令のシーケンスに直接置き換えるだけです。 、ソースコードからのその関数定義に関連するプロシージャコールのマシンコードにトレースのない、単なる通常のプロシージャボディのように。

つまり、static inlineマクロの使用を実際に置き換えることができます。inlineだけでは十分ではありません。

「静的インライン」をGoogleで簡単に検索すると、コンパイラのドキュメントページが表示されます。これはあなたの質問に答えるのに十分であると思い、「いいえ、それは実際には役に立たない」と言います。 inlineの使用、特にstatic inlinehttp://www.greenend.org.uk/rjk/tech/inline.html

13
dividebyzero

free関数(namespaceスコープ)について話す場合、あなたの仮定は正しいです。 static inline関数は実際にはあまり価値がありません。そう static inlineは、単にstatic関数であり、自動的にODRを満たし、inlineはODRの目的のために冗長です。

ただし、メンバーメソッド(classスコープ)について話すとき、static inline関数には値があります。
classメソッドをinlineとして宣言したら、classを含むすべての翻訳単位で完全なボディを表示する必要があります。

staticの場合、classキーワードは異なる意味を持つことに注意してください。
Edit:ご存じかもしれませんが、static内のclass関数には内部リンケージがない、つまりクラスはできません変換(.cpp)単位に応じて、staticメソッドのコピーが異なります。
ただし、static/globalスコープの無料のnamespace関数には、翻訳単位ごとに異なるコピーがあります。

例えば.

// file.h
static void foo () {}
struct A {
  static void foo () {}
};

// file1.cpp
#include"file.h"
void x1 ()
{
  foo();  // different function exclusive to file1.cpp
  A::foo();  // same function
}

// file2.cpp
#include"file.h"
void x2 ()
{
  foo();  // different function exclusive to file2.cpp
  A::foo();  // same function
}
10
iammilind

Gccのmanページを読んだだけで、コンパイラフラグを使用した静的インラインの使用について具体的に説明しています。フラグの場合、関数をインライン化し、静的であり、呼び出されるすべてのインスタンスでインライン化されている場合、作成されたオブジェクトファイルで決して使用されない関数定義を取り除きます。その少しだけ生成されたコードのサイズ。

1
Luke Small