Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check if stream reference is NULL doesn't compile anymore

Tags:

I am compiling an outdated project with my latest gcc g++ compilers, (version > 6)

There is a class CodeWriter with an ostream reference variable.

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

The class is quite large so I included only the relevant variables and functions.

As you can see the destructor seems to be comparing the reference to NULL. This project compiled fine when I used it long back with old gnu toolchain.

But now it is throwing an error saying that there is no matching operator != to compare ostream and long int.

Can anyone explain the rationale behind the change, and how I can fix this?

I would be happy to provide additional information/ include the whole class if required.

like image 310
Vikash Balasubramanian Avatar asked Jan 26 '17 10:01

Vikash Balasubramanian


2 Answers

The code is not comparing the reference itself with NULL, but comparing the referenced-object with NULL. References can't be NULL, and it's impossible to compare the reference itself with NULL.

And

This project compiled i when i used it long back with old gnu toolchain.

Because the behavior changed since C++11.

Before C++11, std::ostream could be implicitly converted to void* via operator void*(), which returns a null pointer if error has occurred on the stream. So the original intent of the code is to check whether the stream has no errors.

Since C++11 the conversion function was changed to explicit operator bool(), which returns false if error has occured. Note the function is declared as explicit, which means implicit conversion to bool is not allowed, so the code won't compile with C++11 again because std::ostream can't be converted to bool implicitly (and then to be compared with NULL (an integer literal)).

With a C++11-compatible compiler you can just change the code to

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

Note that for contextual conversions even explicit conversion functions are considered. For the above code, m_stream will be converted to bool via explicit operator bool(), then the value would be used for the condition of if.

like image 122
songyuanyao Avatar answered Sep 23 '22 01:09

songyuanyao


Streams can always be evaluated in a boolean context, so just change it to:

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

C++11 made the conversion to bool explicit. This is equivalent to if (!m_stream.fail()). Prior to C++11, this short-hand checkability was achieved by providing an (implicit!) conversion to void*, which is why your old code used to work.

The reason the code is checking for this, rather than just calling m_stream.flush(); directly, is perhaps that the stream may have exceptions enabled for failure and that might throw, [update:] but, as @Arne pointed out, flush itself may fail and throw, too. If there are no exceptions, you can just skip the boolean check entirely.[/update]

like image 37
Kerrek SB Avatar answered Sep 23 '22 01:09

Kerrek SB