检查流引用是否为NULL不再编译

时间:2017-01-26 10:25:59

标签: c++ c++11 reference null language-lawyer

我正在用我最新的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工具链使用它时,这个项目编译得很好。

但是现在它发出一条错误消息,指出没有匹配operator !=来比较ostreamlong int

任何人都可以解释改变背后的理由,以及我如何解决这个问题?

如果需要,我很乐意提供更多信息/包括全班。

3 个答案:

答案 0 :(得分:32)

代码不是将引用本身与NULL进行比较,而是将引用对象与NULL进行比较。引用不能是NULL,并且无法将引用本身与NULL进行比较。

  

当我用旧的gnu工具链使用它时,这个项目编译了我。

因为自C ++ 11以来行为发生了变化。

在C ++ 11之前,std::ostream可以通过operator void*()隐式转换为void*,如果流上发生错误,则会返回空指针。所以代码的初衷是检查流是否没有错误。

自C ++ 11以来,转换函数已更改为explicit operator bool(),如果发生错误,则返回false。请注意,该函数声明为explicit,这意味着不允许隐式转换为bool,因此代码将无法再次使用C ++ 11进行编译,因为std::ostream无法转换隐式地到bool(然后与NULL(整数字面)进行比较)。

使用兼容C ++ 11的编译器,您只需将代码更改为

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

请注意,对于contextual conversions,甚至会考虑显式转换函数。对于上述代码,m_stream将通过bool转换为explicit operator bool(),然后该值将用于if的条件。

答案 1 :(得分: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]

答案 2 :(得分:6)

流类在pre-C ++ 11中的一个基类中有一个operator void*()。当然,void*值可以与NULL进行比较。

在当前的C ++中,这是一个explicit operator bool(),它在if语句的上下文中工作,但不在一般表达式中。

使用void*是为了避免在我们没有bool运营商时发生explicit的某些不需要的转化。