30

私のC++アプリケーションには、他の値を表すコードとして機能する値がいくつかあります。コードを翻訳するために、私はswitchステートメントとstlマップのどちらを使用するかについて議論してきました。スイッチは次のようになります。

int code;
int value;
switch(code)
{
case 1:
    value = 10;
    break;
case 2:
    value = 15;
    break;
}

マップはとになり、stl::map<int, int>変換はキー値として使用されるコードを使用した単純なルックアップになります。

どちらがより良い/より効率的/よりクリーン/受け入れられていますか?なんで?

4

12 に答える 12

9

個人的には、マップを使用します。これは、データのルックアップを意味するためです。スイッチを使用すると、通常、プログラムの動作の違いが示されます。さらに、データマッピングの変更は、スイッチよりもマップの方が簡単です。

パフォーマンスが実際の問題である場合、プロファイリングは有用な答えを得る唯一の方法です。ブランチの予測ミスが頻繁に発生する場合、切り替えは高速ではない可能性があります。

これについて考える別のアプローチは、コードと関連する値をデータ構造に結合することがより意味をなさない場合、特にコードと値の範囲が静的である場合です。

struct Code { int code; int value; };

Code c = ...

std::cout << "Code " << c.code << ", value " << c.value << std::end;
于 2010-03-17T20:54:14.620 に答える
8

コードが十分に連続していて、その範囲が許せば、昔ながらの単純な配列を使用した方がはるかに優れています。

int lookup[] = {-1, 10, 15, -1 222};

次に、switchステートメントは次のように簡単に書き直すことができます。

値=ルックアップ[コード];

他のすべてのオプションは、ある程度の追加コストをもたらします。

于 2010-03-17T20:48:09.827 に答える
5

それはむしろコードが何であるか、そしていくつあるかに依存します。優れたコンパイラには、switchステートメントを最適化するために使用するさまざまなトリックがあり、その一部は、ストレートのif/thenステートメントでは使用されません。ほとんどの場合、簡単な計算を実行したり、ケース0、1、2またはケース3、6、9などのルックアップ/ジャンプテーブルを使用したりするのに十分な明るさ​​です。

もちろん、そうでないものもあり、多くは異常な値や不規則な値のセットによって簡単に失敗します。また、いくつかのケースを処理するためのコードが非常に類似しているように見える場合、カットアンドペーストはメンテナンスの問題につながる可能性があります。多くのコードがあるが、それらをアルゴリズムでグループに分割できる場合は、たとえば、次のようなものではなく、いくつかの/ネストされたswitchステートメントを検討することができます。

switch (code) {
    case 0x0001: ...
    case 0x0002: ...
    ...
    case 0x8001: ...
    case 0x8002: ...
    ...
}

あなたが使用するかもしれません:

if (code & 0x8000) {
    code &= ~0x8000;
    switch (code) {
        case 0x0001: ... // actually 0x8001
        case 0x0002: ... // actually 0x8002
        ...
    }
}
else {
    switch (code) {
        case 0x0001: ...
        case 0x0002: ...
        ...
    }
}

多くの言語インタープリターは、この方法でオペコードをデコードします。これは、1バイトのオペコードに追加情報がさまざまなビットにパックされている可能性があり、すべての可能な組み合わせとそのハンドラーを転記することは反復的で壊れやすいためです。一方、過度のビットマングリングは、コンパイラによる最適化を無効にし、逆効果になる可能性があります。

これが実際のパフォーマンスのボトルネックであることが確実でない限り、時期尚早の最適化は避けたいと思います。適度に堅牢で実装が迅速であると思われる方法で実行してください。アプリケーションの実行速度が遅すぎる場合は、プロファイルを作成し、それに応じて最適化します。

于 2010-03-17T21:16:34.137 に答える
2

switchステートメントの方が高速ですが、これがアプリケーションのパフォーマンスのボトルネックになっていない場合は、それほど気にする必要はありません。

長期的にコードを保守しやすくするものを探してください。

サンプルが短すぎるため、その点で意味のある呼び出しを行うことはできません。

于 2010-03-17T20:51:04.697 に答える
2

非常に長いswitchステートメントは、コードとデータの分離を混乱させるように思われるため、私は自分でテーブルを検索することに偏っています。また、テーブルは将来の変更やメンテナンスに適していると思います。

もちろん、すべての私見。

于 2010-03-17T21:21:56.123 に答える
2

静的で定数のペアのテーブルを使用することをお勧めします。これは、ルックアップテーブルの別の形式です。

struct Table_Entry
{
    int code;
    int value;
};

static const Table_Entry  lookup_table[] =
{
  {1, 10},
  {2, 15},
  {3, 13},
};

static const unsigned int NUM_TABLE_ENTRIES =
    sizeof(lookup_table) / sizeof(lookup_table[0]);

std::mapこれの利点は、実行時に初期化する必要があるテーブルとは異なり、コンパイル時にテーブルが生成されることです。数量が多い場合はstd::lower_bound、テーブルが注文されていれば、エントリを見つけるために使用できます。

もう1つの利点は、この手法がデータ駆動型であることです。データは、検索エンジンを変更せずに変更できます。コードまたはプロセスの変更には深刻な回帰テストが必要になる場合がありますが、データの変更には必要ない場合があります。YMMV。

これは、コンパイラが生成するものと似ています。

于 2010-03-18T00:09:39.930 に答える
1

tr1を使用できる場合は、unordered_mapを使用して値をハッシュできます(ハッシュintも非常に高速になる可能性があります)。これにより、ほとんどのルックアップが一定時間になるはずです。

ただし、これがプログラムのボトルネックであることを示すプロファイリングデータがない限り、設計の観点から最も意味のあるアプローチでコーディングしてください。

于 2010-03-17T21:25:25.377 に答える
0

値を割り当てるだけの場合は、マップと言います。私の理由は、コードを変更せずに拡張できるということですが、switchステートメントはそうではありません。

ところで、列挙型はどうですか?

于 2010-03-17T20:47:25.647 に答える
0

「コード」の量が多くなると、switch-case構造の生成コードがかなり大きくなる可能性があると思います。その場合は、stl::mapの方が適切だと思います。

于 2010-03-17T20:50:11.623 に答える
0

通常、マップまたはルックアップアレイ、あるいはハイブリッドルックアップモンスターを提案します(もちろん、読みやすさではなく速度やコードサイズを最適化していると仮定します)が、GCCの新しいバージョンはスマートであることに注意してください。このようなスイッチ/ケースの割り当てをルックアップテーブルに置き換えるのに十分です。これは完全にまばらなキーにはあまり適していませんが、キーが0、1、2、3、4、5、11、12、13、14、15、193、194、 195、196、197、198 .. ..

もちろん、変換を行うためにいくつかの算術が好きである可能性がある場合は、さらに良くなります(通常)。このようなことをするときは、シフト、エンディアンの交換、またはより伝統的な数学を見落とさないでください。

于 2010-03-24T22:16:27.283 に答える
0

unordered_mapは、ハッシュテーブルを使用しており、スイッチの代わりにルックアップが非常に高速になるため、おそらくここのように適しています。

于 2018-10-12T02:46:58.280 に答える
-1
  • 整数を配列/ベクトルに読み込みます
  • 配列/ベクトルを並べ替える
  • 基になる配列でbsearchを使用する
于 2010-03-17T21:19:57.960 に答える