4

式の評価に関する興味深い問題に遭遇しました:

reference operator()(size_type i, size_type j) {
  return by_index(i, j, index)(i, j); // return matrix index reference with changed i, j
}

matrix& by_index(size_type &i, size_type &j, index_vector &index) {
  size_type a = position(i, index); // find position of i using std::upper_bound
  size_type b = position(j, index);
  i -= index[a];
  j -= index[b];
  return matrix_(a,b); // returns matrix reference stored in 2-D array
}

i, j が更新されるように、matrix(i,j) は buy_index の呼び出し後に評価されると思いました。これは正しいようです。デバッガで確認しました。ただし、一部のタイプのマトリックス、特に size_type を別のもの (int など) にキャストする必要があるタイプでは、by_index の更新が失われます。コードを変更すると、問題がわずかに解消されます。

reference operator()(size_type i, size_type j) {
  matrix &m = by_index(i, j, index);
  return m(i, j); 
}

最初のオペレーターがなぜ不正行為をするのか知っていますか? ありがとう

機能するプロトタイプと機能しないプロトタイプ

inline reference operator () (size_t i, size_t j); // ublas, size_type is std::size_t
reference operator () (int i, int j); // other prototype, size_type is int

デバッガーのバックトレース スタックでは、次のようになります。

  • operator() へのエントリ時に i = 1 //わかりました
  • by_index からの終了後、i = 0 //わかりました
  • i = 1 マトリックスへのエントリ:: operator() //正しくありません。0 にする必要があります
4

5 に答える 5

3

私の意見では、これは評価の順序に要約されます。

標準は言う -

(5.4) 特に明記されていない限り、個々の演算子のオペランドと個々の式の部分式の評価の順序、および副作用が発生する順序は規定されていません。

これは法案に正確に適合します。i と j の値は、by_index() の呼び出し前または呼び出し後に評価できます。あなたにはわかりません - これは特定されていません。

あなたの問題を解決するフォームは私の目にははるかに読みやすく、最初のフォームの正しさに関係なくそれを使用したと付け加えます...

于 2010-01-21T05:25:21.937 に答える
2

別のタイプへの参照をキャストすると、コンパイラがより効率的に最適化するために使用する厳密なエイリアシングルールに違反していると思われます。異なるタイプの2つの変数/参照があり、コンパイラーはそれらが同じメモリーを参照していないと想定します(ただし、実際には参照しています)。次に、コンパイラーは、誤った結果を生成する誤った仮定の下でコードを最適化します。

-fno-strict-aliasingこれらの最適化を無効にして、状況が改善されるかどうかを確認するために、(または同等の)コンパイルを試みることができます。

于 2010-01-21T04:31:23.050 に答える
2

最後に、これが指定されている標準の場所を見つけました(n1905ドラフト):

(5.2.2-8) - 引数の評価順序は規定されていません。引数式の評価のすべての副作用は、関数に入る前に有効になります。後置式と引数式リストの評価順序は規定されていません。

上記の後置式は の左側の部分です()。したがって、「外部」関数呼び出しでは、by_index(i, j, index)引数(i, j)が最初に評価されるかどうかは指定されていません。

関数が戻った後にシーケンス ポイントがあるため、by_index(i, j, index)戻り時にすべての副作用が完了し(i, j)ますが、その関数が呼び出される前にパラメーターが既に評価されている可能性があります (値はレジスタまたは sth に格納されています)。

于 2010-01-21T15:35:40.660 に答える
0

補足として、これは簡潔で明快さを覆す典型的なケースであり、ブライアン・カーニハンは避けるよう強く勧めています(彼はこれらの問題に関する優れた本「プログラミング作法」を書きました)。このようなコードでは、評価の順序が明確に定義されていないため、予測できない結果の「副作用」が発生します。行った変更は、このような状況に推奨されるアプローチです。

于 2011-07-14T16:58:01.250 に答える
0
于 2010-01-21T05:24:57.443 に答える