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