簡體   English   中英

C ++表達式評估順序

[英]C++ expression evaluation order

我遇到了一個關於表達式評估的奇怪問題:

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
}

我認為在調用buy_index之后將對matrix(i,j)進行評估,以便更新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

在調試器中,backtrace堆棧如下所示:

  • 進入operator()后i = 1 //好吧
  • 從by_index完成后i = 0 //好的
  • 進入matrix :: operator()//不正確時i = 1,應為0

在我看來,這歸結為評估順序。

標准說 -

(5.4)除非另有說明,否則單個操作員的操作數和個別表達式的子表達式的評估順序以及副作用發生的順序是未指定的。

這完全符合法案。 可以在調用by_index()之前或之后評估i和j的值。 你無法分辨 - 這是未指明的。

我補充一點解決您的問題的形式表現在我眼中更具可讀性,我會不顧第一種形式的正確性,使用它...

我懷疑對不同類型的引用是否會破壞編譯器用來更有效地優化的嚴格別名規則 你有兩個不同類型的變量/引用,並且編譯器假定它們不引用相同的內存(但它們實際上是這樣做的)。 然后,編譯器在錯誤的假設下優化代碼,從而產生錯誤的結果。

您可以嘗試使用-fno-strict-aliasing (或等效項)進行編譯以禁用這些優化,並查看它是否改善了這種情況。

最后我發現標准中指定的位置(n1905草案):

(5.2.2-8) - 參數的評估順序是未指定的。 參數表達式求值的所有副作用在輸入函數之前生效。 post fi x表達式和參數表達式列表的評估順序未指定。

提到的后綴表達式()左側的部分。 因此,在“外部”函數調用中,如果by_index(i, j, index)或它的參數(i, j) by_index(i, j, index)則不指定它。

函數返回后有一個序列點,所以當by_index(i, j, index)返回時,所有副作用都已完成,但(i, j)參數可能已經被評估過(並且值已存儲在寄存器或......那個功能之前甚至會被召喚。

通過這樣的參數列表傳遞數據是非常非常不清楚的。 依賴於引用類型與不同大小的基礎之間的隱式轉換是非常非常不安全的。

無論如何,如果你正在調用by_index(size_t &,…帶有一個int參數,你就是一個臨時的引用。這應該是一個警告,但也許你是在一個較舊的編譯器。嘗試一個顯式的強制轉換。

reinterpret_cast< size_t & >( i ) /* modify i before next fn call */

但當然,這並不能保證做正確的事情。 實際上,你需要從signed中對unsigned進行整理,而不是假設sizeof(int) == sizeof(size_t)因為它通常不是。

作為一個額外的評論,這是典型的案例,簡明扼要清晰,Brian Kernighan強烈建議我們避免(他寫了一本關於這些問題的優秀書籍,“編程實踐”)。 評估順序在這樣的代碼中沒有很好地定義,導致不可預測結果的“副作用”。 您所做的更改是針對此類情況的推薦方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM