我正在用我最新的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 !=
来比较ostream
和long int
。
任何人都可以解释改变背后的理由,以及我如何解决这个问题?
如果需要,我很乐意提供更多信息/包括全班。
答案 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
的某些不需要的转化。