2017-01-26 22 views
19

Mam kompilacji przestarzały projekt z mojego najnowszego gcc, g ++ kompilatory (wersja> 6)Sprawdź, czy referencyjny strumień jest NULL nie skompilować już

istnieje klasa CodeWriter ze zmienną ostream odniesienia.

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

Klasa jest dość duża, więc uwzględniłem tylko odpowiednie zmienne i funkcje.

Jak widać, destruktor wydaje się porównywać odniesienie do NULL. Ten projekt świetnie się spisał, gdy użyłem go z powrotem ze starym toolchainem gnu.

Ale teraz rzuca błąd, mówiąc, że nie ma dopasowania operator != do porównania ostream i long int.

Czy ktoś może wyjaśnić racjonalne uzasadnienie zmiany i jak mogę to naprawić?

Chętnie udzielę dodatkowych informacji/uwzględnię całą klasę, jeśli będzie to wymagane.

+9

Źle zrozumiesz kod - porównuje obiekt strumienia z wartością NULL (która wywoła przeciążony operator w pewnym lub innym rodzaju). Nie ma czegoś takiego jak referencja zerowa (a więc nie można tego sprawdzić). –

+1

Re: "Uwzględniłem tylko odpowiednie zmienne i funkcje" Tak! Dziękuję Ci! Dokładnie tak! –

+2

Należy również zauważyć, że dla porównania _pointers_ do null powinieneś używać 'nullptr' teraz w C++ 11 lub nowszym zamiast makra' NULL'. (Tak, wiem, że nie masz wskaźnika, ale mówię do celu twojego czeku zerowego). –

Odpowiedz

32

Kod nie porównuje samego odniesienia z NULL, ale porównuje obiekt referencyjny z NULL. Odniesienia nie mogą być NULL i nie można porównać samego odniesienia z NULL.

I

Ten projekt skompilowany I kiedy użyłem go długo z powrotem starej gnu toolchain.

Ponieważ zachowanie zmieniło się od C++ 11.

Przed C++ 11, std::ostream mogą być niejawnie konwertowane do void* poprzez operator void*(), która zwraca zerowy wskaźnik, jeśli wystąpił błąd w strumieniu. Oryginalną intencją tego kodu jest sprawdzenie, czy strumień nie zawiera błędów.

Od C++ 11 funkcja konwersji została zmieniona na explicit operator bool(), która zwraca false, jeśli wystąpił błąd.Zauważ, że funkcja jest zadeklarowana jako explicit, co oznacza, że ​​niejawna konwersja na bool jest niedozwolona, ​​więc kod nie będzie się kompilował z C++ 11, ponieważ std::ostream nie może zostać niejawnie przekonwertowany na bool (a następnie w porównaniu z NULL (liczba całkowita).

Z kompilatora 11-kompatybilnym C++ można po prostu zmienić kod do

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

Zauważ, że dla contextual conversions nawet jawne funkcje konwersji są uznawane. W przypadku powyższego kodu, m_stream zostanie przekonwertowane na bool przez explicit operator bool(), wówczas wartość będzie używana dla stanu if.

14

Strumienie mogą być zawsze oceniane w kontekście logicznym, więc po prostu go zmienić na:

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

C++ 11 wykonany konwersję do bool explicit. Jest to odpowiednik if (!m_stream.fail()). Przed wersją C++ 11 ta krótkowzroczność została osiągnięta poprzez zapewnienie (domyślnej!) Konwersji na void*, dlatego stary kod działał.

Powodem, dla którego kod sprawdza to, zamiast wywoływania bezpośrednio m_stream.flush();, jest być może, że strumień może mieć wyjątki włączone dla niepowodzenia i które mogą rzucić, [aktualizacja:], ale, jak @Arne wskazał, flush się może również zawieść i rzucić. Jeśli nie ma wyjątków, można po prostu całkowicie pominąć sprawdzanie logiczne. [/ Update]

+1

'jeśli (m_stream)' jest równoważne 'if (! M_stream.fail())' (które pozwala 'eof()'), a nie 'if (m_stream.good())', chociaż nie ma to znaczenia dla "czystego" "strumienie wyjściowe, ponieważ nie są' eof() '. Ponadto, jeśli celem nie jest rzucanie, to rozwiązanie jest niewystarczające, ponieważ samo spłukiwanie może spowodować ustawienie 'badbita' i wyjątki mogą być włączone dla' badbita'. –

+0

@ArneVogel: Masz rację, dzięki! Naprawiony. –

+2

Założę się, że powodem sprawdzenia, czy strumień jest poprawny przed wypróżnieniem, jest to samo, co powód sprawdzania, czy wskaźnik jest pusty przed usunięciem: chcąc być "bezpiecznym" bez zrozumienia specyfikacji biblioteki. –

6

Klasy strumieni miały numer operator void*() w jednej z klas podstawowych w wersji przed C++ 11. Oczywiście wartość void* można porównać do NULL.

W bieżącym C++ jest to zamiast tego explicit operator bool(), który działa w kontekście instrukcji if, ale nie w wyrażeniu ogólnym.

Użycie numeru polegało na uniknięciu niepożądanych konwersji z bool, które miały miejsce, gdy nie mieliśmy operatorów explicit.

Powiązane problemy