Vik*_*h B 18 c++ null reference language-lawyer c++11
我正在用我最新的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();
}
}
};
Run Code Online (Sandbox Code Playgroud)
这个类非常大,所以我只包含了相关的变量和函数.
正如您所看到的,析构函数似乎是在比较引用NULL.当我用旧的gnu工具链使用它时,这个项目编译得很好.
但现在它抛出一个错误,说没有匹配operator !=比较ostream和long int.
任何人都可以解释改变背后的理由,以及我如何解决这个问题?
如果需要,我很乐意提供更多信息/包括全班.
son*_*yao 32
代码不是将引用本身与之NULL比较,而是将引用对象与之进行比较NULL.引用NULL不可能,并且不可能将引用本身与之比较NULL.
和
当我用旧的gnu工具链使用它时,这个项目编译了我.
因为自C++ 11以来行为发生了变化.
C++ 11之前,std::ostream可被隐式转换为void*经由操作者无效*() ,它返回一个空指针,如果在流错误发生.所以代码的初衷是检查流是否没有错误.
从C++ 11开始,转换函数被更改为explicit operator bool(),false如果发生错误则返回.注意函数被声明为explicit,这意味着bool不允许隐式转换为,所以代码不会再次使用C++ 11编译,因为std::ostream无法bool隐式转换(然后与NULL(整数文字)进行比较) .
使用兼容C++ 11的编译器,您只需将代码更改为
if (m_stream) {
m_stream.flush();
}
Run Code Online (Sandbox Code Playgroud)
请注意,对于上下文转换,甚至会考虑显式转换函数.对于上面的代码,m_stream将转换为boolvia explicit operator bool(),然后该值将用于条件if.
Ker*_* SB 14
可以始终在布尔上下文中评估流,因此只需将其更改为:
if (m_stream) {
m_stream.flush();
}
Run Code Online (Sandbox Code Playgroud)
C++ 11转换为bool explicit.这相当于if (!m_stream.fail()).在C++ 11之前,这种简短的可检查性是通过提供(隐式!)转换来实现的void*,这就是您的旧代码以前工作的原因.
代码检查这个而不是直接调用的m_stream.flush();原因可能是流可能有异常启用失败而且可能抛出,[update:]但是,正如@Arne指出的那样,flush它本身也可能失败并抛出.如果没有异常,你可以完全跳过布尔检查.[/ update]
流类operator void*()在pre-C++ 11中有一个基类.当然,void*价值可以与之比较NULL.
在当前的C++中,这是explicit operator bool()在if语句的上下文中工作的,而不是在一般表达式中.
使用a void*是为了避免bool在我们没有explicit运营商时发生的一些不必要的转换.