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
}

我认为 matrix(i,j) 将在调用 buy_index 后进行评估,因此 i, j 将被更新。这似乎是正确的,我在调试器中验证了。但是,对于某些类型的矩阵,特别是那些必须将 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

在调试器回溯堆栈中看起来像这样:

  • i = 1 在进入 operator() //okay
  • 从 by_index 完成后 i = 0 //好的
  • i = 1 在进入矩阵时:: operator() //不对,应该是 0
4

5 回答 5

3

In my opinion, this boils down to order of evaluation.

The standard says -

(5.4) Except where noted, the order of evaluation of operands of individual operators and subexpressions of individual expressions, and the order in which side effects take place, is unspecified.

Which fits the bill exactly. The values of i and j may be evaluated before the call to by_index(), or after it. You can't tell - this is unspecified.

I will add that the form that solves your problem is far more readable in my eyes, and I would have used it regardless of correctness of the first form...

于 2010-01-21T05:25:21.937 回答
2

我怀疑对不同类型的引用会破坏编译器用来更有效优化的严格别名规则。您有两个不同类型的变量/引用,编译器假定它们不引用相同的内存(但实际上它们确实如此)。然后编译器在产生错误结果的错误假设下优化代码。

您可以尝试使用-fno-strict-aliasing(或等效)进行编译以禁用这些优化,看看它是否可以改善这种情况。

于 2010-01-21T04:31:23.050 回答
2

Finally I found where in the standard this is specified (n1905 draft):

(5.2.2-8) - The order of evaluation of arguments is unspecified. All side effects of argument expression evaluations take effect before the function is entered. The order of evaluation of the postfix expression and the argument expression list is unspecified.

The postfix expression mentioned is the part to the left of (). So in the "outer" function call it is not specified if by_index(i, j, index) or it's arguments (i, j) are evaluated first.

There is a sequence point after a function returns, so when by_index(i, j, index) returns all side effects are complete, but the (i, j) parameters might already have been evaluated (and the values been stored in a register or sth.) before that function even go called.

于 2010-01-21T15:35:40.660 回答
0
于 2010-01-21T05:24:57.443 回答
0

As an additional remark, this is the typical case where been concise overrules clarity, something Brian Kernighan strongly advises us to avoid (He wrote an excellent book on these matters, "The Practice of Programming"). The evaluation order is not well defined in such code, what leads to the "side effect" of unpredictable results. The change you have made is the recommended approach to situations like this one.

于 2011-07-14T16:58:01.250 回答