4

私は2つの文字列を同様に比較する関数を実装することになっていますstrcmpが、空白文字は無視するので、

strcmpignorews("abc   ", " a b c")

同じ結果が得られるはずです。

これが私の実装です:

namespace {
    void SkipWhitespace(const char *&s) {
        for (; std::isspace(*s, std::locale::classic); ++s);
    }
}

int strcmpignorews(const char *s1, const char *s2) {
    for (; *s1 != '\0' && *s2 != '\0'; ++s1, ++s2) {
        SkipWhitespace(s1);
        SkipWhitespace(s2);

        if (*s1 != *s2) {
            break;
        }
    }

    return (*s1 < *s2) ? -1 : ((*s1 == *s2) ? 0 : 1);
}

ここで問題は、SkipWhitespace 関数をインライン化することに意味があるかどうかです。ループやスイッチを含む関数に使用してはならない場所をどこかで読んだことがあると思いinlineますが、場所と理由を思い出せません。

4

5 に答える 5

14

歴史的に、Inline は、関数本体を呼び出しサイトに挿入する必要があることをコンパイラに示すものでした。ただし、これはもはや意味のある注釈ではありません。inline最新のコンパイラは、修飾 の有無に関係なく、関数をインライン化するかどうかに関係なくインライン化します。

強調するために、コンパイラがインライン最適化を実行するかどうかは完全にあなたの手に負えません

最近の使用では、インラインには 1 つの機能しかありません。関数が複数のコンパイル単位で定義されている場合のように、リンカが複数のシンボルを無視するようにするために使用できます。この手法は、循環依存関係を解消するために使用できます。他の目的でインラインを使用しないでください。

于 2010-12-23T13:37:03.897 に答える
3

inlineキーワードは常に、コンパイラに対する単なる提案でした。これは、コンパイラがそのように選択した場合、提案を無視する可能性があることを意味します。その上、コンパイラーが関数をインライン化できる場合、ユーザーが要求していなくても関数をインライン化することがあります。

つまり、コンパイラが関数をインライン化するには、関数の本体を認識している必要があります。関数が別のコンパイル単位で定義されている場合、コンパイラはおそらくそのコンパイル単位の外での関数の定義を認識していません。この場合、コンパイラは、関数を定義するコンパイル単位内の呼び出し元でのみ関数をインライン化できます。したがって、コンパイラが関数をインライン化できるようにする場合は、クラス定義で関数を定義するか、inlineキーワードを追加してヘッダーで定義する必要があります。インライン関数はODRに違反しません。

インライン関数はヘッダーに常駐する必要があり、通常、ヘッダーは多くのコンパイル単位に含まれるため、インライン関数によって静的結合が増加することも考慮する必要があります。つまり、インライン関数の定義を変更すると、依存するすべてのコンパイル ユニットを介してコンパイルでカスケードが発生します。これは重要です。関数の定義はインターフェイスの一部であると想定されていませんが、インライン関数はこの結合を強制します。

その最後の点だけでも、最後に、関数をインライン化しないでください。つまり、アプリケーションまたはライブラリの実行時のパフォーマンスに十分にイライラするまで、その時点でプロファイラーを実行して、特定の関数がインラインでパフォーマンスを向上させるかどうかを確認する必要があります。インライン関数をインライン化すると、関数呼び出しを生成するために必要なコードよりも小さなオブジェクト コードが得られる場合、インライン関数も実行可能ファイルのサイズを縮小できますが、ほとんどの (埋め込み?) コンテキストではそれほど重要な決定要因ではありません。

プロファイラーは、特定の関数がインライン化されている場合にパフォーマンスを向上させることができることを通知できますが、特定のインライン化された関数がインライン化されていない場合にパフォーマンス (サイズ、ランタイム、開発など) を向上させることができるかどうかを通知することはできません。

于 2010-12-23T14:31:07.017 に答える
3

一般に、インライン化する前のプロファイル

インライン化は、常にコンパイラへの提案です。それはあなたを無視するか、あなたに同意する権利を留保します。とにかく、許可なくコードの他の部分をインライン展開している可能性があります。

余分な入力を気にしない場合は、メソッドまたは関数をインラインとして宣言するためのガイドラインを次に示します。

  1. メソッドの内容は、呼び出し、初期化、クリーンアップ、およびメソッドからの復帰に、以下の命令サイクルを使用します。
  2. このメソッドには、他のメソッドへのジャンプや分岐はありません。
  3. このメソッドにはループがありません (最近では、小さなループがプロセッサのキャッシュに収まります)。
  4. メソッドは、インライン化されているか、インライン化できるメソッドのみを使用します。これには、ライブラリ関数が含まれます。
  5. マクロ ( #define) を変換しています。
  6. メソッドは上記のテスト (5 を除く) に合格し、徹底的にテストされています。(ヘッダーを変更したので、すべての依存関係を再構築すると言えますか?)

私のスタイルは、クラスのゲッターとセッターをインライン化することです。揮発性 (動作しない、または変更される可能性がある) または複雑なコードはインライン化されません。

于 2010-12-23T19:26:04.320 に答える
3

そのような状況で使用すべきではないとは言いませんが、コードが比較的高速な場合、コードをインライン化することには大きな利点があります。

これは、インライン化によって関数呼び出しのオーバーヘッドが取り除かれるためです。関数の呼び出しと戻りに 1 秒かかるが、インライン化するコードに 10 分かかる場合、大幅な改善は見られません。ただし、インライン化するコードにも 1 秒かかる場合は、基本的にパフォーマンスが 2 倍になります。

これはコンパイラへの提案inlineであることを覚えておいてください。コンパイラは、あなたが間違っていると判断した場合、または単に不快である場合でも自由に無視できます。私はそれをめったに使用せず、その必要性を見つけることもめったになく、and と同じカテゴリに追いやります(少なくとも C では)。autoregister

于 2010-12-23T13:40:24.773 に答える
2

コンテキストでは、を使用しても害はなく、おそらくいくつかの利点がありますinline

コンパイラがインライン化する関数の複雑さには制限があります。複雑なループやスイッチを含む機能は、そうでない機能よりもその限界に達する可能性が高くなります。したがって、あなたが読んだことはすべて間違っているわけではありません。資格が必要なだけです。

スタイル的には、whileループの代わりにループを使用しforます。

while (isspace(*s, std::locale::classic))
    ++s;

これにより、空白文字以外の文字のみをスキップするコードのバグも修正されます。(この回答が入力されている間にバグが修正されました! )

于 2010-12-23T13:39:46.933 に答える