2017-01-26 11 views
19

Я компиляции устаревший проект с моим последним Gcc г ++ компиляторов (версия> 6)Проверьте опорный поток NULL не компилируется больше

Существует класс CodeWriter с ostream ссылочной переменной.

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

Класс довольно большой, поэтому я включил только соответствующие переменные и функции.

Как вы видите, деструктор, кажется, сравнивает ссылку на NULL. Этот проект был составлен отлично, когда я использовал его с помощью старой gnu toolchain.

Но теперь это ошибка, говорящая о том, что нет operator !=, чтобы сравнить ostream и long int.

Может ли кто-нибудь объяснить обоснование изменений и как я могу это исправить?

Я был бы рад предоставить дополнительную информацию/включить весь класс, если потребуется.

+9

Вы неправильно понимаете код - он сравнивает объект потока с NULL (который будет вызывать перегруженный оператор того или иного типа). Нет такой вещи, как нулевая ссылка (и поэтому ее невозможно проверить) –

+1

Re: «Я включил только соответствующие переменные и функции» Да! Спасибо! Абсолютно верно! –

+2

Также обратите внимание, что для сравнения _pointers_ с нулем вы должны использовать 'nullptr' сейчас в C++ 11 или более поздней версии вместо макроса' NULL'. (да, я знаю, что у вас нет указателя, но я говорю с намерением вашей нулевой проверки). –

ответ

32

Код не сравнивает ссылку с NULL, но сравнивает ссылочный объект с NULL. Ссылки не могут быть NULL, и сравнивать ссылку с NULL невозможно.

И

Этот проект скомпилирован я, когда я использовал его долго назад со старым Gnu набора инструментов.

Поскольку поведение изменилось с C++ 11.

Перед C++ 11, std::ostream может быть неявно преобразован в void* через operator void*(), который возвращает нулевой указатель, если произошла ошибка в потоке. Таким образом, первоначальная цель кода - проверить, нет ли в потоке ошибок.

С C++ 11 функция преобразования была изменена на explicit operator bool(), которая возвращает false, если произошла ошибка.Обратите внимание, что функция объявлена ​​как explicit, что означает, что неявное преобразование в bool не разрешено, поэтому код не будет компилироваться с C++ 11 снова, потому что std::ostream не может быть преобразован в bool неявно (а затем для сравнения с NULL (целочисленный литерал)).

С 11-совместимым компилятором C++, вы можете просто изменить код

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

Обратите внимание, что для contextual conversions рассматривается даже явные функции преобразования. Для вышеуказанного кода m_stream будет преобразован в bool через explicit operator bool(), тогда значение будет использовано для состояния if.

14

Streams всегда можно оценить в логическом контексте, так что просто изменить его на:

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())', хотя это не имеет значения для "pure "выходные потоки, потому что они не являются' eof() '. Кроме того, если намерение не бросать, то решение недостаточно, потому что сам флеш может привести к тому, что «badbit» будет установлен, и исключения могут быть разрешены для «badbit». –

+0

@ АрнеВогель: Вы правы, спасибо! Исправлена. –

+2

Готов поспорить, что причина проверки правильности потока перед его промывкой такая же, как и причина проверки того, является ли указатель нулевым до его удаления: он хочет быть «безопасным», не понимая спецификации библиотеки. –

6

Классы потоков имели operator void*() в одном из базовых классов в pre-C++ 11. Конечно, значение void* можно сравнить с NULL.

В текущем C++ это вместо explicit operator bool(), который работает в контексте оператора if, но не в общем выражении.

Использование void* состояло в том, чтобы избежать нежелательных преобразований от bool, которые произошли, когда у нас не было explicit операторов.