2010-04-21 226 views
1

我在一行中使用流操作符< <和位移操作符< <。 我有點困惑,爲什麼代碼A)不會產生與代碼B相同的輸出)?operator <<:std :: cout << i <<(i << 1);

A)

int i = 4; 
std::cout << i << " " << (i << 1) << std::endl; //4 8 

B)

myint m = 4; 
std::cout << m << " " << (m << 1) << std::endl; //8 8 

類敏:

class myint { 
    int i; 
public: 
    myint(int ii) { 
     i = ii; 
    } 
    inline myint operator <<(int n){ 
     i = i << n; 
     return *this; 
    } 
    inline operator int(){ 
     return i; 
    } 
}; 

在此先感謝
哎呀

+0

幾乎重複的:http://stackoverflow.com/questions/2603312/the-result-of-int-c0- coutcc /。對於大多數實際用途來說,它們是相同的,儘管使用「++」而不是「<<」作爲修改操作符。 – 2010-04-21 21:19:35

+2

@Jerry Coffin:它們非常相似,但有整個「vs < <混淆和事實上<<通常不會改變它的論點 – 2010-04-21 21:23:50

回答

8

你的第二個例子是未定義的行爲。

您已將myint類中的<<運算符定義爲<<=。當您執行i << 1時,i中的值未被修改,但在執行m << 1時,m中的值爲已修改。

在C++中,對於沒有中間順序點的變量(對於它們的參數而言,哪些函數調用和操作符不是這樣)讀取和寫入(或寫入多次)是未定義的行爲。它是不確定的代碼是否

std::cout << m << " " << (m << 1) << std::endl; 

將輸出第一m之前或之後mm << 1更新。事實上,你的代碼可能會做一些奇怪的事情,或者崩潰。未定義的行爲可能導致字面上的任何事情,所以避免它。

一個適當的方法來定義<<運營商myint是:

myint operator<< (int n) const 
{ 
    return myint(this->i << n); 
} 

(該this->不是絕對必要的,只是我的風格,當我重載運算符)

+1

但是重載操作符是函數調用,有許多序列點。 – 2010-04-21 21:20:15

+2

'std :: cout << m <<「」<<(m << 1)'相當於'std :: cout.operator <<(m).operator <<(「」).operator <<( m.operator <<(1))'在每個最外層的操作符被調用時,有一個序列點,但是在傳遞給操作符的參數的評估之間沒有序列點,包括內部調用換句話說,在'f(a()).g(b())'中,在調用'f'和調用'g''之間存在一個序列點。 ,但是調用'a'和'b'的順序是不確定的。 – 2010-04-21 21:23:14

+0

也許你應該更新你的答案,因爲沒有你的評論中的解釋,很明顯,許多順序點都不能保證關鍵表達式之間沒有一個。 – 2010-04-21 21:29:56

2

你< <運營商其實是一個運營商。如果您更換

std::cout << i << " " << (i <<= 1) << std::endl; //8 8 

行,你應該得到8 8

+6

你已經強調了這個問題,但你的「答案」有未定義的行爲 – 2010-04-21 21:18:32

1

嘛(M < < 1)M前進行評估,因而,M擁有8已經如您在操作< <你覆蓋你自己的價值。

這是你身邊的錯誤行爲,運營商< <應該是const並且不能改變你的對象。

5

因爲int < < X返回一個新的int。 myint < < X修改當前的myint。你的myint < <運營商應該固定做前者。

你第一次得到8的原因很明顯是你的實現中首先調用1。實現可以以任意順序自由執行。

0

因爲<<運營商myint修改了它的lhs。因此,在評估m << 1後,m實際上將具有值8(而i << 1僅返回8,但不會使我等於8)。由於沒有指定m<<1是否在cout << m之前執行(因爲未指定函數或操作符的參數以何種順序進行評估),因此未指定輸出是8 8還是4 8

2

因爲mmyInt你的第二個例子可以寫成:

std::cout << m << " " << (m.operator<<(1)) << std::endl; 

評價的子表達式的順序m(m.operator<<(1))是不確定的,所以沒有說法,其中「m」你會得到在m中使用的第1個表達式(這是一個簡單的m表達式)。所以你可能會得到「4 8」的結果,或者你可能會得到「8 8」。

請注意,語句不會導致未定義的行爲,因爲在修改m和「讀取」之間存在序列點(至少一個函數調用)。但是子表達式的評估順序沒有指定,所以編譯器必須產生一個結果(它不會崩潰 - 至少不合法),但是沒有說明應該產生兩種可能的結果中的哪一種。

因此,該聲明與未定義行爲一樣有用,也就是說它不是非常有用。

0

C++語言沒有定義操作符評估的順序。它只定義它們的關聯性。

由於您的結果取決於何時在表達式中計算了operator<<函數,因此結果未定義。

代數operator $功能應始終const並返回一個新的對象:

inline myint operator <<(int n) const { // ensure that "this" doesn't change 
    return i << n; // implicit conversion: call myint::myint(int) 
} 
相關問題