1

次のコードを検討してください。

#include <iostream>

int main(int argc, char ** argv) {

  std::set<int*> ints;

  for (int i = 0; i < 10; i ++) {
    int * k = new int(i);
    ints.insert(k);
  }

  for (auto i : ints) {
    // some order-sensitive operations, for example:
    std::cout << (*i) << " ";
  }

  return 0;
}

2 番目のループは、要素がセットから取得される順序に影響されます。そのようなプログラムの実行結果が、プログラムの実行ごとに異なる可能性はありますか?

私の知る限り、std::set要素を内部的に並べ替えます。メモリ内の割り当ては必ずしも増加するアドレスを持つとは限らないため、このプログラムの出力が0 1 2 3 4 5 6 7 8 9?

4

3 に答える 3

5

はい、異なる場合がありますが、UBが原因ではありません。

ここで定義されている実装は2つあります。

  • 順序付けはどのようstd::less<int*>に行われますか(ほとんどの実装では「自然な」順序付けが表示されますが)
  • によって返されるアドレスはoperator new、毎回同じである場合とそうでない場合があります。これは、実装で使用するアロケータによって異なる可能性が高く、両方の方法(決定論的で、一見ランダムに見える)が実際に見られます。(たとえばvalgrindを使用してプログラムを実行する場合、順序は常に同じである可能性がありますが、ネイティブで実行する場合とは異なることに注意してください)。

したがって、これが関心のある特定の順序であることに依存しないでください。

于 2013-02-26T10:46:27.913 に答える
2

これは、標準の意味での「未定義の動作」ではありません(何かが発生する可能性があります)。

ただし、メモリを割り当てるときに取得するポインタアドレスは明確に指定されていません。この規格では、無料ストアの編成方法や、さまざまな割り当てのアドレスの順序については何も述べられていません。

于 2013-02-26T10:45:50.210 に答える
0

マニュアル、ルークを使用してください。

MSDNのstd::setドキュメント

STLセットは次のとおりです。

(...)

その要素は、指定された比較関数に従ってコンテナ内のキー値によって順序付けられているため、ソートされています。

ポインタは単なるintであるため、これらの変数はアドレスでソートされます。メモリマネージャはこれらの変数を非常に異なる場所に割り当てることができるため、それらの順序(値の観点から)が維持されるという保証はありません。

ただし、独自の比較関数を提供できるようです。

MSDNのstd::set :: set()ドキュメント

次に、セットの要素を自分に最も適した方法で並べ替えることができます。

于 2013-02-26T10:45:41.113 に答える