Why does outputting a string in an unnamed std :: ofstream give me a hex number?

I was trying to add some debug output to a C ++ 03 project and got some weird result. Here's a simplified test code:

#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";
}

      

For some reason, this is what I get after compiling:

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

      

Why am I getting a hexadecimal number when outputting a string to an unnamed std::ofstream

object? And why does the subsequent output of the second line work?

+3


source to share


1 answer


The usual operator<<

one we use to pass C strings to std::ostream

is declared as a free function

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

      

An unnamed std::ofstream

object is a temporary variable, and temporary entries cannot bind to a nonconst reference, so this operator overload is not involved in overload resolution. The closest match is performed instead, the member function

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

      

which takes a pointer to erase and just prints its value. Since member functions can be called with a temporary object, this works. This explains the hexadecimal number in the output. Now, this statement returns the link std::basic_ostream&

. Since it is no longer a temporary object and is instead a reference to some nonconst object, you can successfully call a normal free function overload operator<<

that takes const char*

. This is why the second line is printed as expected.



Note that as of C ++ 11, the code will work as expected since we have an additional overload operator<<

that takes an rvalue reference:

template< class CharT, class Traits, class T >
basic_ostream< CharT, Traits >& operator<<( basic_ostream<CharT,Traits>&& os, 
                                            const T& value );

      

and a temporary binding to an rvalue reference.

To make your code work in C ++ 03, you can use a member function std::ostream::flush()

that returns a reference to a nonconst object and has no user-visible side effects on the object fstream

:

#include <fstream>

int main()
{
    std::ofstream("/tmp/test.txt").flush() << "hello"
                                           << " ... OK, this now works too\n";
}

      

+8


source







All Articles