Подтвердить что ты не робот

Проверить, является ли ссылка на поток 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.

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

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

4b9b3361

Ответ 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.