MxNx
MxNx

Reputation: 1374

Access violation exception while trying to redirect std::cerr to file

I'd like to redirect the output of std::cerr and std::cout to files. For this purpose, I have used the rdbuf functions as in the code sample below. Unfortunately, I receive the exception

Exception thrown: read access violation.

*(__imp_std::basic_ios<char,std::char_traits<char> >::rdbuf(...)) was 0xCCCCCCCC.

whenever I try to write anything to std::cout or std::cerr.

Here is a code sample that produces my problem:

void redirect()
{
    auto t = std::time(nullptr);
    auto tm = *std::localtime(&t);

    std::ostringstream oss;
    oss << std::put_time(&tm, "%Y-%m-%d_%H-%M-%S.log");
    auto cerrFileName = "cerr-" + oss.str();
    auto coutFileName = "cout-" + oss.str();


    std::ofstream cerrFile(cerrFileName, std::ios::ate); // file is created 
    std::cerr.rdbuf(cerrFile.rdbuf());

    std::ofstream coutFile(coutFileName, std::ios::ate); // file is created
    std::cout.rdbuf(coutFile.rdbuf());
}

int main()
{
    redirect();

    std::cout << "Test"; // The exception is thrown here.

    return 0;
}

This sample creates two files as it should but does not write anything into neither of them. What am I doing wrong?

Upvotes: 1

Views: 425

Answers (2)

Maxim Egorushkin
Maxim Egorushkin

Reputation: 136276

std::ofstream own its buffer and when std::ofstream objects go out of scope they destroy the buffers, resulting in std::cout and std::cerr using invalid pointers to the buffers.

Make sure that the buffers do not get deleted prematurely.

Upvotes: 3

Some programmer dude
Some programmer dude

Reputation: 409196

With e.g.

std::cout.rdbuf(coutFile.rdbuf());

you make std::cout share the same buffer as coutFile, you only set the pointer.

Unfortunately std::basic_streambuf is not reference counted. That means when the redirect function returns then coutFile is destructed and closed which include destructing the buffer object.

That leaves e.g. std::cout with a stray pointer to a non-existing buffer object.

The streams you share the buffer objects with needs to have a lifetime over the full program. And before you exit the program you need to restore the original buffers for std::cout and std::cerr (rdbuf returns pointers to the old buffers).

Upvotes: 2

Related Questions