为什么输出一个字符串到未命名的std :: ofstream而不是给我一个十六进制数?

时间:2017-07-13 16:06:48

标签: c++ string fstream ofstream

我试图将一些调试输出添加到C ++ 03项目中并得到一些奇怪的结果。这是简化的测试代码:

#include <fstream>

int main()
{
    {
        std::ofstream file("/tmp/test.txt");
        file << "hello" << " ... OK, this works\n";
    }
    std::ofstream("/tmp/test.txt",std::ios_base::app) << "hello"
                                                      << " ... no, I mean hello!\n";
}

出于某种原因,这是编译后得到的结果:

$ g++ test.cpp -o test && ./test && cat /tmp/test.txt
hello ... OK, this works
0x80487fe ... no, I mean hello!

为什么在将字符串输出到未命名的std::ofstream对象的情况下会得到十六进制数?为什么第二个字符串的后续输出有效?

1 个答案:

答案 0 :(得分:8)

我们用于将C字符串传递给operator<<的常用std::ostreamdeclared as自由函数

template< class Traits >
basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,  
                                        const char* s );

未命名的std::ofstream对象是临时变量,临时变量不能绑定到nonconst引用,因此此运算符重载不参与重载决策。而是采用最接近的匹配,成员函数

std::basic_ostream& std::basic_ostream::operator<<(const void*);

,它采用类型擦除指针并只打印其值。由于可以在对象是临时对象的情况下调用成员函数,因此可以解决这个问题。这解释了输出中的十六进制数。现在,此运算符返回引用std::basic_ostream&。由于它不再是临时对象而是对某些非对象对象的引用,因此可以成功调用operator<<的{​​{1}}的常规自由函数重载。这就是第二个字符串按预期打印的原因。

请注意,由于C ++ 11代码将按预期工作,因为我们有一个额外的const char*重载,它接受一个右值引用:

operator<<

,临时绑定到右值引用。

要使代码在C ++ 03中工作,您可以使用成员函数template< class CharT, class Traits, class T > basic_ostream< CharT, Traits >& operator<<( basic_ostream<CharT,Traits>&& os, const T& value ); ,它返回对象的nonconst引用,并且对{没有任何用户可见的副作用{1}}对象:

std::ostream::flush()