I’m trying to write a really simple thread-safe logger. Ideally, I wanted it to work just like std::cout, wherein you could just overload the << operator and have everything magically show up in the log. I’m on a Windows machine, so here’s the approach I tried:
// Threadsafe logger
class Logger
{
public:
Logger()
{
InitializeCriticalSection(&s);
}
~Logger()
{
DeleteCriticalSection(&s);
}
void Log(std::ostream const& os)
{
EnterCriticalSection(&s);
//std::cout << static_cast<std::stringstream const&>(os).str();
std::cout << os.rdbuf();
LeaveCriticalSection(&s);
}
private:
CRITICAL_SECTION s;
};
Notice that I’ve tried two approaches to the Log() function. The reason I accept an ostream is because that’s what a stringstream seems to produce after the << operator is called. Both variants of the Log() function fail in the same way when I run this code:
#include <iostream>
#include <sstream>
#include <Windows.h>
int main(int argc, char* argv[])
{
Logger logger;
//logger.Log(std::stringstream("Test"));
logger.Log(std::stringstream("Another ") << "test");
std::cin.get();
}
Outputting the first line (“Test”) works correctly and displays properly using both variants of the Log function. The second line outputs a mangled output:
testher
which is obviously test written over Another. What am I missing about the way these streams work? I tried making a flush call hoping that would fix things, but it did nothing.
How can I get this attempt at a thread-safe logger working correctly with the streams?
The problem isn’t with the logger, rather it’s with your use of stringstream.
When std::stringstream is initialized, the stream’s position indicator is positioned at the beginning of the stream.
Now when you start writing to the string using ‘<<‘, you start writing at the position indicator, replacing whatever was there before.
To work around this, you can initialize the stringstream with
std::stringstream(“Another “, stringstream::in | stringstream::out | std::stringstream::ate)
(as per http://www.cplusplus.com/reference/iostream/stringstream/stringstream/ )