2017-01-26 44 views
19

我編譯一個過時的項目,我的最新的gcc G ++編譯器(版本> 6)檢查流引用爲null不會編譯了

有一類CodeWriterostream參考變量。

class CodeWriter 
{ 
    //private: 
protected: 
    ostream &m_stream; 
public: 
    CodeWriter(ostream &stream):m_stream(stream){} 
    ~CodeWriter(){ 
    if(m_stream != NULL){ 
     m_stream.flush(); 
    } 
    } 
}; 

該類很大,所以我只包含了相關的變量和函數。

正如你所看到的析構函數似乎在比較NULL的引用。 這個項目編譯的很好,當我用它舊的GNU工具鏈回來。

但現在它拋出一個錯誤,說沒有匹配的operator !=來比較ostreamlong int

任何人都可以解釋變化背後的基本原理,以及我如何解決這個問題?

如果需要,我很樂意提供更多信息/包括整個班級。

+9

您誤解了代碼 - 它將流對象與NULL進行比較(將調用某種或另一種重載操作符)。沒有這樣的事情作爲空引用(所以,它是不​​可能檢查一個) –

+1

回覆:「我只包括相關的變量和函數」是的!謝謝!非常正確! –

+2

另請注意,爲了將_pointers_與null進行比較,您應該在C++ 11或更高版本中使用'nullptr',而不是使用'NULL'宏。 (是的,我知道你沒有指針,但我正在說你的空檢查的意圖)。 –

回答

32

該代碼未將引用本身與NULL進行比較,但是將引用對象與NULL進行比較。參考文獻不能是NULL,並且不可能將參考本身與NULL進行比較。

而且

該項目編譯我什麼時候我用它長回老GNU工具鏈。

因爲自從C++ 11以來行爲發生了變化。

在C++ 11之前,可以通過operator void*()std::ostream隱式轉換爲void*,如果在流上發生錯誤,則返回空指針。所以代碼的最初意圖是檢查流是否沒有錯誤。

由於C++ 11的轉換功能已更改爲explicit operator bool(),如果發生錯誤,它將返回false。注意該函數聲明爲explicit,這意味着不允許隱式轉換爲bool,因此代碼不會再與C++ 11一起編譯,因爲std::ostream不能隱式轉換爲bool(然後與NULL(一個整數字面))。

隨着C++ 11兼容的編譯器可以將代碼只是改變

if (m_stream) { 
    m_stream.flush(); 
} 

注意,對於contextual conversions甚至顯式轉換函數的考慮。對於上述代碼,m_stream將通過explicit operator bool()轉換爲bool,則該值將用於條件if

14

流總是可以在布爾上下文進行評估,所以只是改變爲:

if (m_stream) { 
    m_stream.flush(); 
} 

C++ 11所作的轉換爲bool explicit。這相當於if (!m_stream.fail())。在C++ 11之前,通過提供(隱式!)到void*的轉換(這就是爲什麼您的舊代碼用於工作)來實現這種簡短的可檢查性。

代碼檢查這個的原因,而不是直接調用m_stream.flush();,可能是因爲該流可能有異常啓用失敗,並可能拋出[update:],但是,正如@Arne指出的那樣,flush本身可能會失敗並拋出。如果沒有例外,您可以完全跳過布爾檢查。[/ update]

+1

'if(m_stream)'等於'if(!m_stream.fail())'(允許'eof()'),而不是if(m_stream.good())',儘管這與「純「輸出流,因爲它們不是'eof()'。另外,如果意圖不是拋出,那麼解決方案是不夠的,因爲刷新本身可能會導致'badbit'被設置,並且異常可能被啓用以用於'badbit'。 –

+0

@ArneVogel:你說得對,謝謝!固定。 –

+2

我敢打賭,在刷新之前測試流是否有效的原因與在刪除指針之前測試指針是否爲null的原因相同:希望在不瞭解庫規範的情況下爲「安全」。 –

6

流類在Pre-C++ 11中的一個基類中有一個operator void*()。當然,void*的值可以與NULL相比較。

在當前的C++中,這是explicit operator bool(),它在if語句的上下文中工作,但不在通用表達式中。

使用void*是爲了避免當我們沒有explicit運算符時發生的bool發生的一些不需要的轉換。