tags:

views:

218

answers:

2

I've been writing a custom std::streambuf as part of a logging system. However, I'm having problems with the first piece of output from a stream not being formatted correctly.

Here's a reduced test-case that doesn't use any custom streambuf or ostream classes:

#include <iostream>

int main()
{
    std::streambuf *coutbuf = std::cout.rdbuf();
    std::ostream(coutbuf) << "test" << ": writing to cout using a separate ostream." << std::endl;
    return 0;
}

Compiling this using g++:

$ g++ --version
g++ (Ubuntu 4.4.1-4ubuntu8) 4.4.1

$ g++ -o fail reduced-case.cpp

$ ./fail
0x400c80: writing to cout using a separate ostream.

Note that the first string literal ("test") is being formatted as a generic pointer (the address of the string is output in hex), while the second string literal is formatted correctly.

The only thing I can think of is that it's invalid to directly use a newly constructed std::ostream like that (ie, without putting it into a variable). If this is the case, I'd very much like to know what exactly makes it invalid (I assume it's nothing to do with iostreams specifically, but rather order-of-evaluation or interactions with constructors or something). If that's not the problem, then what is?

+7  A: 

The problem is that you must not write to a temporary stream object. This:

std::ostream(coutbuf) << "blah";

doesn't work as expected, since the left-hand argument for operator<<() is an rvalue. However, all the operators overloaded as a free function take a non-const reference to a stream as their left-hand argument:

std::ostream& operator<<(std::ostream&, ...);

Since rvalues do not bind to non-const references, they cannot be called.

I suspect that your std lib implementation implements << for const char* as a free function and has thus to fall back to some << that's a member of std::ostream. It seems in your implementation that's the one outputting any pointer as a void*.

Bottom line: Don't attempt to write to temporary stream objects.

sbi
+1  A: 

You can't use a temporary stream object like this. Give a name to the temporary variable.

#include <iostream>

int main()
{
    std::streambuf *coutbuf = std::cout.rdbuf();
    std::ostream os(coutbuf);
    os << "test" << ": writing to cout using a separate ostream." << std::endl;
    return 0;
}
dalle