c++http-redirectwofstream

Why does redirecting wcout/wcerr to /dev/null cause program to crash?


consider my logging class

void LogWriter::InitLogWriter(void)
{
    wcout.flush();
    wcerr.flush();
    COUT_BACKUP = wcout.rdbuf(); // save original cout buffer
    CERR_BACKUP = wcerr.rdbuf(); //save original cerr buffer
    FileStreamOpen = false;
    switch(m_nTraceLvl)
    {
    case OffLevel:
        StopOutput();
        break;
    case ErrorLevel:
        OutputErrorsToFile(s_TraceFile);
        break;
    case DetailLevel:
        OutputAllToFile(s_TraceFile);
        break;
    default:
        StopOutput();
        break;
    }
    wcout << "Initialize Log Writer" << endl;
}
void LogWriter::OutputAllToFile(TCHAR* fileName)
{
    wstreambuf* fb = GetFileBufferStream(fileName);

    wcout.rdbuf(fb); // push wcout buffer to file
    wcerr.rdbuf(fb); // push cerr buffer to file

    FileStreamOpen = true;
}
void LogWriter::OutputErrorsToFile(TCHAR* fileName)
{
    wstreambuf* fb = GetFileBufferStream(fileName);
    wcerr.rdbuf(fb);
    FileStreamOpen = true;
    wofstream fout("/dev/null");
    wcout.rdbuf(fout.rdbuf()); // redirect 'cout' to a 'fout'
}
void LogWriter::StopOutput(void)
{
    wofstream fout("/dev/null");

    wcout.rdbuf(fout.rdbuf()); // redirect 'cout' to a 'fout'
    wcerr.rdbuf(fout.rdbuf()); // redirect cerr to fout
}
wstreambuf* LogWriter::GetFileBufferStream(TCHAR* fileName)
{
    filestr.open(fileName);
    return filestr.rdbuf();   // get file's streambuf
}
void LogWriter::Dispose()
{
    wcout << "Kill Log Writer" << endl;
    wcout.rdbuf(COUT_BACKUP); // restore the original stream buffer
    wcerr.rdbuf(CERR_BACKUP);

    if(FileStreamOpen)
    {
        filestr.close();
    }
}

Now if i set my Tracing to DetailLevel (2) all is fine. All my logging goes to the file. But if i choose OffLevel or ErrorLevel my program crashes.. my debugger doesn't turn on so i added cout << "." on every line (i hate doing that, but it works) and it points me to

wcout.rdbuf(fout.rdbuf()); // redirect 'cout' to a 'fout'

as being my culprit... I switched around redirecting wcout first with wcerr being redirected and it worked (but wcerr was not called yet)

so that is my question? am I supposed to dispose wcout first? I tried flushing first..that didn't work.. so i don't know. What am I doing wrong?

Also as a bonus.. how come all my output doesn't go to the file until I close my LogWriter? IE LogWriter::Dispose()


Solution

  • You crash because wofstream fout("/dev/null"); is created on the stack and is destroyed as soon as you leave the function.

    Treat /dev/null exactly like you treat the file. That is, call OutputErrorsToFile("/dev/null") inside StopOutput(). In fact you don't even need /dev/null: just use wcout.rdbuf(nullptr), which should work faster too.

    To write into the file immediately call .flush() or use std::flush manipulator.