C ++ iostream Corruption using stringstream

I am trying to write a really simple thread safe logger. Ideally, I wanted it to work the same way as std::coutin which you could just overload the operator <<and everything that magically appeared in the magazine. I am on a machine under Windows, so here is 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;
};

Note that I tried two approaches to the function Log(). The reason I accept ostreamis because what is created stringstreamafter the operator is called <<. Both options of the function Log()do not work 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();
}

( "" ) , Log. :

testher

, , test Another. , ? flush, , , .

?

+3
4

, stringstream. std:: stringstream, .

, , '< <', , , .

, stringstream std:: stringstream ( "", stringstream:: in | stringstream:: out | std:: stringstream:: ate)

( http://www.cplusplus.com/reference/iostream/stringstream/stringstream/)

+2

, , , , , ostream , , , , , .

, , . , std::cout << os.rdbuf();, , .

, , RAII ( , ), , Log . , Log, , :

Edit: , . transaction, stringstream, - .

#include <windows.h>
#include <iostream>
#include <sstream>

class crit_sect {
    CRITICAL_SECTION cs;

    void lock() { EnterCriticalSection(&cs); }
    void unlock() { LeaveCriticalSection(&cs); }
    friend class lock;

    crit_sect(crit_sect const &); /* = delete; */
    crit_sect &operator=(crit_sect const &other); /* = delete; */
public:
    crit_sect() { InitializeCriticalSection(&cs); }
    ~crit_sect() { DeleteCriticalSection(&cs); }
};

class lock {
    crit_sect &cs;
public:
    lock(crit_sect &c) : cs(c) { cs.lock(); }
    ~lock() { cs.unlock(); }
};

class transaction {
    std::ostringstream buffer;
public:
    transaction(std::string const &s="") : buffer(s, std::ios::out | std::ios::ate) {}

    template <class T>
    transaction &operator<<(T const &t) {
        buffer << t;
        return *this;
    }

    friend std::ostream &operator<<(std::ostream &os, transaction const &t) {
        return os << t.buffer.str();
    }
};

class Log {
    std::ostream &out;
    crit_sect mutex;
public:
    Log(std::ostream &sink) : out(sink) { }

    template <class T>
    void operator<<(T const &t) {
        lock l(mutex);
        out << t;
    }    
};

int main() {
    Log l(std::cout);

    l << "This is a string\n";

    l << (transaction("Another ") << "Test");
    return 0;
}

Log , transaction ( ). , , - , ostringstream ctor, , transaction , , , .

+3

Using variable templates:

void Log_impl(std::ostream &os) {} // recursion base case

template<typename T,typename... Us>
void Log_impl(std::ostream &os,T &&t,Us &&... us) {
    os << std::forward<T>(t);
    Log_impl(os,std::forward<Us>(us)...);
}

template<typename... Ts> void Log(Ts &&... ts) {
    std::stringstream ss;
    Log_impl(ss,std::forward<Ts>(ts)...);
    fprintf(stdout,"%s\n",ss.str().c_str()); // thread safe output
}

using:

Log("Another"," test ",100);

I really have not tested this code ...

+3
source

<<does not send a null byte at the end of the "test" to the temporary string stream ("Other") that you created, so you see "testher".

0
source

All Articles