Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Conversations: Redirections


March 2001 C++ Experts Forum/Conversations

I wasn't too concerned until the third day passed without seeing Jeannine. After some hesitation and mental handwringing, I went to see Frenell about it. She was the obvious choice; both Jeannine and I reported to her just then.

Her stateroom door slid open on the second knock. "Oh, it's you," she said. "What's on?"

"Just looking for Jeannine. Haven't seen her for a few days," I explained.

Frenell regarded me briefly, then said: "Oh, yes. She's been temporarily reassigned."

"She has? Where?"

"Over to the dome. They've been requesting some extra manpower there and at the excavation site. While she's there she has to stay there; access is restricted because the locks and tunnels aren't in great shape, and it's a pain to get people to suit up to get in and out just to shuttle back here."

"Are a lot of people being reassigned? It's been feeling a bit empty out here lately." All I knew was that repairs were apparently still going on in the main dome, since the explosion a few weeks before. Those of us on the surface kept to the outlying buildings and continued with our local work while we were out of contact with the inner system; long-range communications, which went through the dome's systems, were still crippled and under repair.

"A few," she said, and leaned on the side of the doorway. "Why? Want me to put in your name if there's an opening for someone with your skills?"

"Sure," I said without thinking and then wondered at my own quick reaction. Was I that concerned about Jeannine? Or was I just anxious to see her again? Either way, my feelings surprised me.

If Jeannine had been redirected to the dome, I figured I might as well go too if the chance came up. Briefly, I recalled a day, many years ago, when I had learned to deal with another kind of redirection. Oddly enough, it also had a bit to do with restricted access problems.


It was just as Wendy was passing my cubicle that I screamed: "Aaagh! I hate access violations!"

The frustration was too much, and I finally let it boil over into what I hoped was a primal roar. The effect was somewhat diminished in that my voice was still maturing, and it came out more like a mouse's roar.

It was enough to make Wendy stop and look in on me. "Sure and what's the matter, me young friend?" she said with a fake Irish accent. With St. Patrick's Day fast approaching, she was playing up her Irish heritage to the...lilt.

"Wendy, do me a favor," I sighed, "don't you act weird, too. One basket case around here is enough."

"Hey, you okay?" she said quietly, kindly. "What brought this on, buddy?"

"Just right now it's this code, but I guess it's also a bit to do with the Guru," I admitted. "At first, I was scared witless by her. I was sure she was an escapee from the local asylum. Then I kind of got to like her calling me 'my apprentice.' Yeah, it's a bit strange, but essentially harmless. But when I told my friends, they thought it was really condescending, and once I got to thinking about it, I realized they were right."

Wendy smiled. "Ah," she said, "I see. Look, you just haven't seen her from the right perspective yet. You really should try to get to know her outside work." I tried to imagine her home: shelves filled with dusty computer books and magazines; incense burning on altars dedicated to various computer scientists.... My face must have betrayed my thoughts — Wendy burst out laughing. "She does the Guru shtick mainly to annoy Bob and scare interns. I go along with it because it bugs the Hades out of him."

"Oh." I remained unconvinced. The act was just a little too convincing for my liking. But I didn't want to argue, so I sighed and composed myself, and came back to the point: "I've been wrestling with this problem for a few hours. Simple task, really — just reassign cout and cerr so that their output goes to a file, instead."

"Sorry, run that by me again?"

"I'm integrating a library developed by another group. The library was written with a command-line interface in mind, so all the debugging and diagnostic messages get sent to cout and cerr. What's worse, I think Bob was on that team, because there's no rhyme or reason to when messages go to cout and when they go to cerr. In fact, some messages are split between the two streams! So I have to capture and integrate both streams into a single log.

"Anyway, as I said, I'm integrating this library into our GUI application. Unfortunately, the GUI just tosses any output to cout and cerr into the bit bucket. So, what I'm trying to do is redirect the output into a file, instead. Simple job. So simple I can't figure out how to do it. I've boiled the problem down to this small program." I dragged the guest chair over to the monitor for Wendy to sit down.

#include <iostream>
#include <fstream>
int main()
{
    std::ofstream logFile("out.txt");
    std::cout = logFile;
    std::cerr = logFile;
    std::cout << "This goes to cout\n";
    std::cerr << "This goes to cerr\n";
}

"It compiles and runs OK on one compiler, but it gives me an access violation when I use another compiler."

Wendy studied the screen for a moment. "Hmmm... I'm not sure you're allowed to reassign streams like that."

"Indeed, child, it is an unnatural act clearly forbidden by the Holy Standard."

We jumped. But only slightly. Act or no act, I had to admit that the Guru was uncannily good at appearing at exactly the right moment. "So, what I'm trying to do is impossible?" I sighed.

"No," the Guru smiled. "It is quite simple, actually. My apprentice, which compiler did you use in your studies at university?"

"Well, it was actually an older compiler and didn't have very many standard features."

The Guru nodded sagely. "I see. Your compiler would be using what the prophets Langer and Kreft refer to as 'classic IOStreams' [1]. You must become familiar with standard IOStreams — in particular the stream buffer classes. No longer is the stream buffer a lowly implementation detail; it is a blessed class in its own right. The designer of the IOStreams classes, Jerry Schwarz, foresaw that the stream buffer class would be an extremely useful feature. Yet its value and power are often overlooked."

"OK. So what do I do?"

The Guru picked up the dry-erase marker and quickly wrote out some code on my white board:

#include <iostream>
#include <fstream>
int main()
{
    std::ofstream logFile("out.txt");
    std::streambuf *outbuf = std::cout.rdbuf(logFile.rdbuf());
    std::streambuf *errbuf = std::cerr.rdbuf(logFile.rdbuf());

    // do the actual work of the program;
    // GUI code and event loop would go here
    std::cout << "This would normally go to cout but goes to the log file\n";
    std::cerr << "This would normally go to cerr but goes to the log file \n";
    logFile << "This goes to the log file\n";
    // end of program body

    // restore the buffers
    std::cout.rdbuf(outbuf);
    std::cerr.rdbuf(errbuf);
}

"The rdbuf function returns a pointer to the stream buffer managed by the base class, basic_ios. The overloaded version allows you to replace the stream buffer, and the return value is the original stream buffer. The solution is simple — you replace the stream buffers for cout and cerr with the stream buffer of your log file. At the end of your program, you restore the original stream buffers. As you can see, you can still use logFile as a regular output file."

"Cool!" I was beginning to see the power of the stream buffers. "Hey, if I only wanted to redirect one stream, say cerr, could I just simply swap the two buffers and not have to worry about restoring them, like this:"

int main()
{
    std::ofstream logFile("out.txt");
    std::streambuf *saveBuf=cerr.rdbuf(logFile.rdbuf());
    logFile.rdbuf(saveBuf);
    // remainder of program...
}

"Alas, it is not that simple," the Guru sighed. "Your code will not compile. The basic_ios::rdbuf functions are not virtual. ofstream provides only one rdbuf function, which takes no parameters and returns a pointer to the file stream buffer embedded in the ofstream object. This means that std::ofstream::rdbuf(void) hides std::ostream::rdbuf(std::streambuf *).

"You could manipulate your log file through a pointer to std::ostream, like this:"

int main()
{
    std::ofstream logFile("err.log");
    std::ostream * baseManipulator = &logFile;
    baseManipulator->rdbuf(std::cerr.rdbuf(baseManipulator->rdbuf()));
}

"This code will compile, but will not necessarily work properly. The Holy Standard does not specify how ofstream is to be implemented. It is possible that compiler implementers will implement ofstream's functionality such that it ignores the base ostream::rdbuf function and instead works directly on the file stream buffer. The Standard does require ofstream::close to call ofstream::rdbuf to determine which buffer to close. Since this function always returns a pointer to the filebuf embedded in the ofstream object, ofstream will always close its embedded filebuf object, leaving cerr without a valid buffer. Thus, you still need to restore cerr's stream buffer, by inserting this line before main() exits:

std::cerr.rdbuf(baseManipulator->rdbuf());

"If you ever want to redirect cin's input, you must take similar precautions, as ifstream behaves analogously."

The Guru turned to leave, then paused. "I am inviting some people to my home this Saturday. Nothing special, just a social evening. You and Wendy, and your respective significant others, are welcome to attend."

I opened my mouth to gracefully decline. "Gaaah!"

"He means he'll be glad to come," Wendy smiled sweetly. My shin was in too much pain from where she had kicked me, so all I could do was nod helplessly through gathering tears. The Guru smiled and glided away.

I waited until both the Guru and the pain were gone, then growled at Wendy: "I'll get you for this."


"Okay," I told Frenell, "just let me know if you do put my name in."

"Sure will."

I was about to go, but asked: "Say, I wonder if Ling didn't get reassigned too, along with Jeannine I mean. They were watch partners."

"No," Frenell said. "We need her here."

"Thanks. See you tomorrow."

During my next watch, I checked some of the duty rosters that I had access to view. The names made a long and varied list - Jupiter et al. was UN space, so this was a UN mission, with personnel from many zones, predominantly from the American Union and the Asian Federation due to their heavy science budgets. None of the names was overtly marked as reassigned, but I could tell which names were no longer on regular rotation in the duty roster; those had to be the ones working elsewhere.

I paged through idly. It was a quiet watch.

In time, I noticed an odd pattern: No Asians were being reassigned to the excavation site or to the dome.


Acknowledgement

Thanks to Angelika Langer and Klaus Kreft for their clear discussion of this and many other stream-related topics in their book, Standard C++ IOStreams and Locales: Advanced Programmer's Guide and Reference [1].

Note

[1] Angelika Langer and Klaus Kreft. Standard C++ IOStreams and Locales: Advanced Programmer's Guide and Reference (Addison-Wesley, 2000).

Jim Hyslop is a senior software designer at Leitch Technology International Inc. He can be reached at [email protected].

Herb Sutter is an independent consultant and secretary of the ISO/ANSI C++ standards committee. He can be reached at [email protected].


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.