10

これは、トークンが入ってくるときにインデックスを作成するために使用する一般的なパターンです。トークンがマップ内にあるかどうかを確認し、そうでない場合はマップに追加して、マップのサイズを割り当てます。

C++ でこれを行うと、割り当てが行われる前にマップのサイズが予期せずインクリメントされます。

#include <cstdio>
#include <map>
using namespace std;

int main() {
    map<char, int> m;
    printf("Size before adding: %d\n", m.size());
    m['A'] = m.size();
    printf("Size after adding: %d\n", m.size());
    printf("What was added: %d\n", m['A']);

    return 0;
}

これは出力します:

Size before adding: 0
Size after adding: 1
What was added: 1

私が理解しているように、それはゼロである右側を評価し、それを「A」とゼロをマップに入れる関数に渡す必要があります。しかし、割り当てを開始した後に評価しているように見えますが、これは意味がありません。

代入操作の前に右辺を評価するべきではありませんか?

4

4 に答える 4

6

動作は詳細不明で、詳しく言えば不明です。

しかし、あなたの場合は次のようになります。

m['A'] = m.size();

mキーがstd::map存在しない場合に新しいエントリを作成する です。

あなたの場合、キー'A'は存在しないため、エントリを作成し、値への参照を返します(デフォルトで作成されます)。これはm.size()、ケースに割り当てられます。

上記のように、オペランドの評価の順序が指定されていないため、動作は指定されていません。つまり、 のm.size()前に評価される可能性がありますm['A']。そうであればm['A']0ではなくになり1ます。

于 2013-08-04T05:41:19.527 に答える
5

いいえ。

(§5.17/1): 「すべての場合において、代入は右オペランドと左オペランドの値の計算の後、代入式の値の計算の前に順序付けられます。」

ただし、割り当ては右オペランドと左オペランドが評価された後に行われますが、左オペランドと右オペランド自体の評価の間に順序付けは指定されないことに注意してください。したがって、左が最初に評価され、次に右が評価されるか、またはその逆になります。

于 2013-08-04T05:44:45.510 に答える
4

しかし、割り当てを開始してから評価しているようです...

この質問の回答で示されているように、代入での評価の順序は実際には指定されていません (左側の式と右側の式のどちらが最初に評価されるかは指定されていません) 。

が最初に評価される場合m.size()、コードは意図したとおりに動作しますが、この動作は保証されず、別の実装がm['A']最初に評価される可能性があります。これはあなたの場合と同じです。これらのあいまいなケースは回避する必要があります。

代わりにこのようなことをしたほうがいい

auto size = m.size();
m['A'] = size;

これにより、要素の割り当ての前にサイズ クエリが最初に評価されることが保証されます。

改善されたLIVE CODE。.

于 2013-08-04T05:42:33.317 に答える
1

これはstl ヘッダー ファイルから編集され[]たoperatorのおおよその実装です。

mapped_type& operator[](const key_type& key){
auto itr = lower_bound(key);
// itr->first is greater than or equivalent to key.
if (itr == end() || comp_func(key, (*itr).first))
      itr = insert(itr, value_type(key, mapped_type()));
return (*itr).second;
}

ご覧のとおり、新しい要素が最初に挿入されるため、マップのサイズが 1 増加します

Ref std::map::operator[]

key がコンテナー内のどの要素のキーとも一致しない場合、関数はそのキーを持つ新しい要素を挿入し、マップされた値への参照を返します。これにより、マップされた値が要素に割り当てられていない場合でも、コンテナーのサイズが常に 1 増加することに注意してください (要素は既定のコンストラクターを使用して構築されます)。

編集 :

他の人が指摘したm['A'] = m.size();ように、不特定の動作につながります。そのようなステートメントは使用しないでください。代わりに、最初にサイズを計算してから新しいキーに割り当てることができます。

于 2013-08-04T05:51:11.460 に答える