I'm writing a unit test and therefore, cannot change the code within the file that I'm testing. The code that I'm testing has messages in cout that I am trying to redirect into a file to check to make sure that the program is outputting the right messages. Does anyone have a way to redirect stdout in another program that won't cause a lag? I have tried freopen() and that causes my program to hang for some reason.
Asked
Active
Viewed 3,384 times
3
-
1It might be a bit OS specific.. – Petter Nordlander Jun 07 '12 at 22:34
-
1Consider [this](http://stackoverflow.com/questions/3661106/overlapped-readfileex-on-child-process-redirected-stdout-never-fires). Definitly not a dupe, but related. Might help. – John Dibling Jun 07 '12 at 22:40
-
This question is answered [here](http://stackoverflow.com/questions/5257509/freopen-equivalent-for-c-streams). – jxh Jun 07 '12 at 22:38
-
After redirecting, did you call `flush()` after the code under test had run its full course? – wallyk Jun 07 '12 at 23:19
2 Answers
2
You could create a filebuf
then replace cout
's streambuf with it:
{
std::filebuf f;
f.open("output.txt", std::ios::out);
std::streambuf* o = std::cout.rdbuf(&f);
std::cout << "hello" << std::endl; // endl will flush the stream
std::cout.rdbuf(o);
}
You need to restore cout
's original streambuf again (or set it to a null pointer) or it will probably crash when the global streams are flushed and destroyed, because the filebuf
will already have gone out of scope.

Jonathan Wakely
- 166,810
- 27
- 341
- 521
-
-
This has caused it to start to hang again somehow. Is there something you know of that cause it not to hang? – Annika Peterson Jun 07 '12 at 23:03
-
It works for me in a small test. Have you run it in a debugger to see where it hangs? – Jonathan Wakely Jun 07 '12 at 23:17
-
I think the reason it may be hanging is that it is running within another set of macros that I cannot change that also use stdout. Is that possible? – Annika Peterson Jun 07 '12 at 23:22
-
Apparently my standard-fu is failing me here -- where does the standard say that `cout.rdbuf(0)` is equivalent to what you have? – ildjarn Jun 07 '12 at 23:26
-
@ildjarn, I didn't say it's equivalent, I said it "works" i.e. it won't crash. Leaving `cout` referring to the `filebuf` after it goes out of scope is unsafe, restoring the original streambuf _or_ clearing `cout`'s streambuf avoids that problem. – Jonathan Wakely Jun 08 '12 at 00:02
-
Yes, but "works" is a meaningless word without context/guarantees... I understand the rationale for needing to unset the `filebuf`, but I'm unclear as to why `cout.rdbuf(0);` should work. – ildjarn Jun 08 '12 at 00:04
-
@Annika, anything else directly using `stdout` _should_ be unaffected, replacing the streambuf affects operations done through the `cout` object, not the `stdout` file descriptor. – Jonathan Wakely Jun 08 '12 at 00:05
-
@ildjarn, you want [ios::Init] i.e. 27.5.3.1.6 in C++11, which says that after the last `Init` is destroyed `cout.flush()` is called, which is UB if `cout.rdbuf()` is a dangling pointer, but according to [ostream.unformatted] 27.7.3.7 paragraph 7 is a no-op if `rdbuf()` is null. Happy? You owe me two standard references now ;) – Jonathan Wakely Jun 08 '12 at 00:18
-
I've paid my standard-reference dues on this site already, but I'll keep that in mind. ;-] Thanks for the answer. :-] – ildjarn Jun 08 '12 at 00:20
-
Turns out that .rdbuf(0) was part of the problem and only .rdbuf(o) worked for me. I also had another error that was causing the hanging. Thanks for your help! – Annika Peterson Jun 11 '12 at 17:56
1
You can use 'open()' and 'dup2()'. You can use the helpers provided below. An example of how to use them:
void
code_to_test ()
{
std::cout << "Here we go" << std::endl;
std::cerr << "Danger danger" << std::endl;
}
run_test(code_to_test);
The run_test
helper invokes redirection, and runs the test code.
template <typename TEST> void
run_test (TEST t, bool append = false) {
flush_output();
Redirect o(1, "/tmp/test_stdout", append);
Redirect e(2, "/tmp/test_stderr", append);
t();
flush_output();
}
The flush_output
helper flushes the streams.
void flush_output () {
fflush(stdout);
fflush(stderr);
std::cout.flush();
std::cerr.flush();
}
The Redirect
class effects the redirection in the constructor. It restores the original descriptors back in the destructor.
class Redirect
{
int m_what;
int m_old_what;
public:
Redirect (int what, std::string where, bool append = false)
: m_what(what), m_old_what(dup(what)) {
int flags = O_CREAT|O_WRONLY;
if (append) flags |= O_APPEND;
int f = open(where.c_str(), flags, 0660);
dup2(f, m_what);
close(f);
}
~Redirect () {
dup2(m_old_what, m_what);
close(m_old_what);
}
};

jxh
- 69,070
- 8
- 110
- 193