Проверить, является ли ссылка на поток NULL больше не компилируется
Я компилирую устаревший проект с моими последними компиляторами gcc g++ (версия > 6)
Существует класс 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
.
Может ли кто-нибудь объяснить обоснование изменений и как я могу это исправить?
Я был бы рад предоставить дополнительную информацию/включить весь класс, если потребуется.
Ответы
Ответ 1
В коде не сравнивается сама ссылка с NULL
, а сравнение объекта-ссылки с NULL
. Ссылки не могут быть NULL
, и невозможно сравнивать ссылку с NULL
.
и
Этот проект скомпилировал i, когда я использовал его с помощью старой gnu toolchain.
Поскольку поведение изменилось с С++ 11.
До С++ 11 std::ostream
может быть неявно преобразован в void*
через оператор void *(), который возвращает нулевой указатель, если произошла ошибка на потоке. Таким образом, первоначальная цель кода - проверить, нет ли в потоке ошибок.
Так как С++ 11, функция преобразования была изменена на explicit operator bool()
, которая возвращает false
, если произошла ошибка. Обратите внимание, что функция объявлена как explicit
, что означает, что неявное преобразование в bool
недопустимо, поэтому код не будет компилироваться с С++ 11 снова, потому что std::ostream
не может быть преобразован в bool
неявно ( а затем для сравнения с NULL
(целочисленный литерал)).
С С++ 11-совместимым компилятором вы можете просто изменить код на
if (m_stream) {
m_stream.flush();
}
Обратите внимание, что для контекстных конверсий рассматриваются даже явные функции преобразования. Для вышеуказанного кода m_stream
будет преобразован в bool
через explicit operator bool()
, тогда значение будет использоваться для условия if
.
Ответ 2
Потоки всегда можно оценивать в булевом контексте, поэтому просто измените его на:
if (m_stream) {
m_stream.flush();
}
С++ 11 сделал преобразование в bool explicit
. Это эквивалентно if (!m_stream.fail())
. До С++ 11 эта краткосрочная проверка была достигнута путем предоставления (неявного!) Преобразования в void*
, поэтому ваш старый код работал.
Причина, по которой этот код проверяет это, а не просто вызывает m_stream.flush();
напрямую, возможно, что поток может иметь исключения, разрешенные для отказа, и которые могут быть выбраны, [update:], но, как отметил @Arne, flush
сам может потерпеть неудачу и бросить тоже. Если исключений нет, вы можете просто полностью исключить логическую проверку. [/Update]
Ответ 3
В потоковых классах был operator void*()
в одном из базовых классов в pre-С++ 11. Конечно, значение void*
можно сравнить с NULL
.
В текущем С++ это вместо explicit operator bool()
, который работает в контексте оператора if
, но не в общем выражении.
Использование void*
состояло в том, чтобы избежать нежелательных преобразований из bool
, которые произошли, когда у нас не было операторов explicit
.