I ran across this problem while cleaning up the debug macros of an old C/C++ application: We have a Tracer class inheriting from ostrstream (I know it's been deprecated since C++98, but this application was written in 1998!) which we use like this:
Tracer() << "some" << " message" << " here";
Now if the first value in the chain is a constant string like above, the result of calling ostrstream::str() on the Tracer (which is done in the destructor, inserting the result into a queue) contains a hexadecimal representation of the pointer to this string instead of the text. Thus the above statement would yield something like "0x401a37 message here". This didn't occur with the old macros as they always had a long (Thread ID) as the first value which has now been removed.
Stepping into it with gdb showed that for the first insertion, this calls operator<<(void const*) on the ostrstream, while the subsequent insertions call operator<< <...>(basic_ostream<...>&, char const*) (templating removed for readability).
Can somebody explain this behaviour? What would be a clean way to fix this? I have found an easy workaround, which is using << left as the first argument - is this safe? Are there better ways to do this?
Here's a minimized example:
#include <strstream>
#include <iostream>
using namespace std;
class Trace : public ostrstream {
public:
Trace();
virtual ~Trace();
};
Trace::Trace() : ostrstream() {}
Trace::~Trace() {
static_cast< ostrstream& >(*this) <<ends;
char * text = ostrstream::str();
cout << "MESSAGE: "<< text <<endl;
delete[] text;
}
int main(){
Trace() << "some" << " text" << " here";
Trace() << left << "some" << " text" << " here";
Trace() << 123 << " text" << " here";
}