2010-11-13 162 views
10

考慮你有一個像「雙重」任務 - 應該避免嗎?

i = j = 0 

假設您所選擇的語言,這是明確的一些表達。將它分成兩個表達式一般會更好:

i = 0 
j = 0 

我有時在庫代碼中看到了這一點。在簡潔性方面,它似乎沒有多少價值,不應該比兩個語句表現得更好(儘管這可能與編譯器有關)。那麼,是否有理由相互使用一個呢?還是僅僅是個人偏好?我知道這聽起來像一個愚蠢的問題,但它現在糾纏我很長一段時間:-)。

回答

3

這兩種形式反映了對作業的不同觀點。

第一種情況將賦值(至少是內部賦值)作爲運算符(返回值的函數)。

第二種情況將分配視爲語句(執行某項操作的命令)。

在某些情況下,作爲運算符的賦值具有重要性,主要是爲了簡潔,或者用於期望得到結果的上下文中。但我覺得很困惑。出於以下幾個原因:

  • 賦值運算符基本上是副作用運算符,而現在對編譯器進行優化是一個問題。在C和C++等語言中,它們會導致許多未定義的行爲情況或未優化的代碼。
  • 現在還不清楚它應該返回什麼。賦值運算符應返回已賦值的值,還是應返回已存儲位置的地址。根據具體情況,其中一個或另一個可能很有用。
  • +=這樣的複合賦值更糟。目前還不清楚運營商是否應該返回初始值,合併結果,甚至是儲存地點。

賦值語句有時會導致中間變量,但這是我看到的唯一缺點。很明顯,編譯器知道如何有效地優化後續的這些語句。

基本上,我會盡可能地避免作爲運算符賦值。提交的案例非常簡單,並且沒有真正混淆,但作爲一般規則,我仍然會更喜歡。

i = 0 
j = 0 

i, j = 0, 0 

對於支持語言,並行分配。

1

第二種方式更具可讀性和清晰度,我更喜歡它。

但是我會盡量避免 「雙重」 的聲明:

int i, j; 

,而不是

int i; 
int j; 

,如果他們要連續。特別是在MyVeryLong.AndComplexType

+1

且不說'字符* I,J; '對'char * i,* j;'。 – 2010-11-13 11:30:31

+0

@Ignacio:與您的主題相關的好老問題http://stackoverflow.com/questions/377164/whats-your-preferred-pointer-declaration-style-and-why – abatishchev 2010-11-13 11:34:19

2

這取決於語言。在高度面向對象的語言中,雙賦值會導致將同一對象分配給多個變量,因此一個變量中的更改會反映在另一個變量中。

$ python -c 'a = b = [] ; a.append(1) ; print b' 
[1] 
+0

在這種情況下'b = []; a = b'語法更清晰 – kriss 2015-01-01 22:15:15

+0

@kriss:但問題不在於詢問語法。 – 2015-01-01 22:37:50

+0

我在指出,一行合併分配的等價物不是將相同的常數賦值給兩個物體。這依賴於約定,即賦值的結果是分配給第一個變量的值。這是許多人的可能選擇。在支持賦值時隱式強制轉換的語言(如C++)中,如果返回值應該是執行強制轉換之前的對象(我相信這是第一個,但必須在標準參考文檔中檢查爲當然)。 – kriss 2015-01-01 22:54:52

2

大多數人會發現兩種可能性同等可讀。其中一些人會有個人偏好。但乍看之下,人們可能會因爲「雙重任務」而感到困惑。我個人比較喜歡獨立的方法,bacause

  • 它是不是真的冗長相比,雙變
  • 它可以讓我忘記關聯的規則=操作
它是100%可讀
8

從前有一次表現差異,這是使用這種分配的原因之一。編譯器會變成i = 0; j = 0;到:

load 0 
store [i] 
load 0 
store [j] 

所以,你可以通過使用i = j = 0保存的指令,因爲編譯器將它變成:

load 0 
store [j] 
store [i] 

如今的編譯器可以自己做這種類型的優化的。而且,由於當前的CPU一次運行多條指令,性能不能再以指令數量來衡量。一個動作不依賴另一個動作的結果的指令可以並行運行,因此對每個變量使用單獨值的版本實際上可能會更快。

關於編程風格,您應該使用最能表達代碼意圖的方式。

例如,當您只想清除某些變量時,可以鏈接作業,並在該值具有特定含義時將其分配。特別是如果將一個變量設置爲該值的含義與將另一個變量設置爲相同值的含義不同。

3

首先,在語義層面上,取決於您是否想要說ij是相同的值,或者恰好兩者都具有相同的值。

例如,如果ij是二維數組中的索引,則它們都從零開始。 j = i = 0表示i從零開始,j開始於i開始。如果你想從第二行開始,你不一定要從第二列開始,所以我不會在同一個語句中初始化它們 - 行和列的索引獨立發生在兩個行都從零開始。

此外,在語言其中ij表示複雜的對象,而不是整體的變量,或者其中分配可能引起的隱式轉換,它們是不等效的:

#include <iostream> 

class ComplicatedObject 
{ 
public: 
    const ComplicatedObject& operator= (const ComplicatedObject& other) { 
     std::cout << " ComplicatedObject::operator= (const ComplicatedObject&)\n"; 
     return *this; 
    } 
    const ComplicatedObject& operator= (int value) { 
     std::cout << " ComplicatedObject::operator= (int)\n"; 
     return *this; 
    } 

}; 

int main() 
{ 
    { 
     // the functions called are not the same 
     ComplicatedObject i; 
     ComplicatedObject j; 

     std::cout << "j = i = 0:\n"; 
     j = i = 0; 

     std::cout << "i = 0; j = 0:\n"; 
     i = 0; 
     j = 0; 
    } 

    { 
     // the result of the first assignment is 
     // effected by implicit conversion 
     double j; 
     int i; 

     std::cout << "j = i = 0.1:\n"; 
     j = i = 0.1; 

     std::cout << " i == " << i << '\n' 
        << " j == " << j << '\n' 
        ; 

     std::cout << "i = 0.1; j = 0.1:\n"; 
     i = 0.1; 
     j = 0.1; 

     std::cout << " i == " << i << '\n' 
        << " j == " << j << '\n' 
        ; 
    } 

}