簡體   English   中英

過早的優化還是我瘋了?

[英]Premature optimization or am I crazy?

我最近在comp.lang.c ++上看到了一段代碼,它從函數返回一個靜態整數的引用。 代碼是這樣的

int& f()
{
   static int x;
   x++;
   return x;
}

int main()
{
  f()+=1; //A
  f()=f()+1; //B
  std::cout<<f();

}

當我使用很酷的Visual Studio調試器調試應用程序時,我只看到對語句A的一個調用,並且猜測我感到震驚。 我一直以為i+=1等於i=i+1所以f()+=1等於f()=f()+1而且我會看到兩次調用f() ,但是我只看到一。 這到底是什么? 我是發瘋還是調試器發瘋,或者這是過早優化的結果?

這是標准對+=和朋友的評價:

5.17-7:形式為E1 op = E2的表達式的行為與E1 = E1 op E2等效,只不過對E1進行一次評估。[...]

因此,編譯器是正確的。

i+=1功能上與i=i+1 實際上,它的實現方式有所不同(基本上是為了利用CPU級別的優化而設計的)。

但從本質上講,左側僅被評估一次。 它產生一個非常量l值,這是讀取值,加一個值並將其寫回所需的全部。

當為自定義類型創建重載運算符時,這一點更加明顯。 operator+=修改this實例。 operator+返回一個新實例。 通常建議(在C ++中)先編寫oop + =,然后再根據其編寫op +。

(請注意,這僅適用於C ++;在C#中, op+=完全與您假設的一樣:只是op+的簡寫,並且您無法創建自己的op + =。它將自動從Op +中為您創建)

您的想法是合乎邏輯的,但並不正確。

i += 1;
// This is logically equivalent to:
i = i + 1;

但是邏輯上等效和相同並不相同。
該代碼應如下所示:

int& x = f();
x += x;
// Now you can use logical equivalence.
int& x= f();
x = x + 1;

除非您將兩個函數調用明確地放入代碼中,否則編譯器不會進行兩個函數調用。 如果您的函數有副作用(就像您一樣),並且編譯器開始增加額外的工作量,很難看到隱式調用,那么實際上很難理解代碼流,從而使維護變得非常困難。

f()返回對靜態整數的引用。 然后+= 1將一個添加到該存儲位置–無需在語句A中調用兩次。

在我所見過的每種支持+ =運算符的語言中,編譯器都會一次評估左側的操作數,以產生某種類型的地址,然后將其用於讀取舊值和寫入新值。 + =運算符不僅僅是句法糖; 如您所述,它可以實現表達式語義,而通過其他方式很難實現。

順便說一句,vb.net和Pascal中的“ With”語句都具有相似的功能。 如下語句:

' Assime Foo is an array of some type of structure, Bar is a function, and Boz is a variable.
  With Foo(Bar(Boz))
    .Fnord = 9
    .Quack = 10
  End With
將計算Foo(Bar(Boz))的地址,然后將該結構的兩個字段設置為值9和10。 在C中相當於

\n   {\n     FOOTYPE * tmp = Foo(Bar(Boz));\n     tmp-> Fnord = 9;\n     tmp-> Quack = 10;\n   }\n

但是vb.net和Pascal不會公開臨時指針。 盡管可以在VB.net中實現相同的效果而無需使用“ With”來保存Bar()的結果,但是使用“ With”可以避免使用臨時變量。

暫無
暫無

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

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