A few days ago, I was working on a problem to do with a simple menu driven graphical design process written in C++. The problem was that I wanted to be able to offer an undo option. Unfortunately the nature of some of the actions left only two reasonable choices; save the prior state – about 260Kbytes of data – or redo everything from a known point. The individual actions run fast so in an interactive mode redoing would be acceptably fast.
Even with memory measured in gigabytes I am reluctant to store prior states with that amount of data. Just a one level undo is, in my opinion, unreasonable with the resources the average user has available.
However, storing the actions for a redo from scratch has a major advantage, it means that in addition to a simple multi-level undo, we can also provide facilities for editing an action without having to undo back to it.
My immediate thought was that the individual menu choices formed a sequence and could be stored in an STL type container. The trouble with that idea is that I want a simple design without going down the route of smart pointers or proxy objects. I needed a single type that could be stored in a container, and I needed a simple way to create instances of that type.
I fairly soon realised that the C++ string type could act as a place to store the data. But was there some quick, uniform way to create such a string for each menu option?
Once I phrased the question that way, an answer sprang to mind, use a stringstream object to do the conversions. The data being input from the keyboard would be easily inserted into such an object. Furthermore, we could use a stringstream as a source as well as a sink for data so redoing an action would, with a few tweaks, be the same as the original with cin replaced by a stringstream object.
Confused? Perhaps some code snippets will help:
| int
main(){ playpen pic; vector<string> acts; bool finished(false); do { display_choices(); int choice=get_choice(); finished = do_choice(choice, acts, pic); } while(!finished) } |
Inside do_choice() we will find something like:
| if
(recordable(choice)) { stringstream act_data; act_data << char(choice) << " "; // code to handle individual // choices, passing them // act_data by reference. acts.push_back(act_data.str()); } else { // code for cases which // are not recordable, // e.g. save, load, quit, // undo, etc. } |
The key feature is that stringstream objects support two member functions called str(). Here we are using the version that has no parameters, which returns, by value, the string being used as a buffer. We can simply push that string onto the end of our vector of string. The result is that we create a sequence of actions stored as string objects in a vector. We can write that data back to a file and we can process it by removing entries or by editing them (probably with another menu driven process to which we could apply a similar strategy to allow us to undo edits.) We can write a do_all() function that takes a vector<string> containing the actions and repeats them. The top level of such a function will be purpose written but most of the implementation can build on our existing functions that execute the different actions. The primary difference being that they will use a stringstream object as their data source.
The key to that last process comes from using the second form of the str() member function. If you provide a string argument it replaces the current buffer with that one. Again, a small code snippet:
| void
do_all_actions(vector<string>& acts) { stringstream next_act; for(int i=0;i!=acts.size(); ++i) { process_act(next_act.str(acts[i])); } } |
This is no more than the rudiments of a mechanism and you will have to do quite a bit more to flesh it out into high quality, possibly OO, source code.
While I was working out my idea for using stringstream objects as sources and sinks for data I remembered one of the questions that newcomers to C++ frequently ask: How do I covert a number into a string?
An expert will quite likely say “Use Boost's lexical_cast.” I am unconvinced that that is a particularly helpful response. Boost's (see www.boost.org) lexical_cast is an all singing, all dancing template which may, or may not, meet your needs, but is certainly going to consume valuable time while you read the documentation and learn to use it.
Most programmers just want a quick way to convert data to a string the following little template probably does all they want and a bit more as a bonus:
| template<typename
strable> string to_str(strable data) { stringstream converter; converter << data; return convertible.str(); } |
This code converts any type that supports an operator << into a string. Thus, it will work for all the built-in types and also for many user-defined types. It does not try to do anything clever, but could, with a extra work, be extended to take a format string. I am not convinced that it would be worth the effort.
I advocate of simple code that meets most needs, leaving the generalizations for those that need them.
Those working on GUI event driven applications often ignore the C++ stream facilities because they use OS specific mechanisms for data capture and display. Others working in environments where the C++ console objects and fstream types make sense focus entirely on those. I think that the C++ stringstream class has much to offer both groups in that it provides mechanisms for handling data in a single homogeneous form. Like much of C++, the benefit comes from the synergy of combining the different resources the language provides.
WG21 & J16 (C++) and WG14 & J11 (C) are currently in maintenance mode with respect to the relevant Standard. Both are preparing to start work on the next release of their Standard (scheduled for some time at the end of this decade). There are many issues that have to be tackled but to understand the constraints, we need to understand how we got to where we are today.
In this series I intend to tackle various issues that I find important, particularly those that are often not fully understood. I hope that many readers will feel the desire to chip in and do so by emailing either the editor of ACCent or directly to me (francis_at_robinton.demon.co.uk).
The committee members of the above names committees are often accused of not listening to the C and C++ communities. The putative evidence for this is that they do not make the changes an individual wants and believes to be self evidently a ‘good thing.’
Putting aside for one moment that they are all unpaid (indeed, not a few pay serious money from their own pockets to be involved) volunteers, there is a serious issue of how they should know what you want if you do not clearly tell them and listen to the answer. As the saying goes, it takes two to tango.
When thinking about a proposal for extension or change it is important to understand the impact such a change would have on existing code. Every change has a cost, and almost every change will constrain potential future changes. Let me deal with a very simple cost in the remainder of this column before moving on to other costs in future columns.
It has long been a contention of mine that one of the weaknesses of K&R is that the authors do not mention tools such as lint that were designed to ensure consistency between files. The consequence was that several major companies implemented C for their platform of choice without providing those tools. That left C open to criticism because of its potential for dangerous linkage practices.
It was only very recently that I discovered why lint is a distinct tool rather than an implicit part of C implementations. When Ritchie proposed to add the underpinning for stronger linkage requirements he hit upon the legacy
code problem. Adding those features would have broken just about every piece of C code that had been written. That was unacceptable, the cost was considered to be too high.
The fix was to move that responsibility to another tool whose use was entirely optional. That decision reinforced the 'Trust the Programmer' paradigm for code development.
All would have been well had the then future generations of C programmers been taught that lint was an essential tool. It would have been even better if a lint like tool had been bound into the compiler-linker chain by default. It wasn't with the result that most programmers have to go and get a third party tool such as PCLint in order to do a professional job with C development.
A decision made more than two decades ago continues to haunt us today. Yet I am sure that the original decision to not break existing code was the right one, it is just that the consequences might have been better managed.
Will we learn from that experience? Or are we doomed to repeat it again and again?
Over to you, because my space has run out.
By Reg. Charney
I am pleased to announce that we have some exciting changes in this newsletter. First, we are in transition to a new editor – DS Moen; and second, we have a new and exceedingly knowledgeable regular columnist – Francis Glassborow.
While I have guided ACCent since its inception, I felt it needed to be made more exciting, relevant, and interesting. To that end, some else needed to lead the effort. That someone needed to be more intimately involved with the nuts and bolts of the Valley and its currents and moods. I believe that I found her.
I am pleased to welcome Deirdre Saorise Moen as our new editor. She has been a software engineer for more than twenty years and has worked on scientific, shrink-wrap, and general applications. She became interested in open source while working at an ISP where she was introduced to many forms of UNIX as well as Linux. She is also a science fiction enthusiast and author.
After moving to the Bay area, She helped found BayPIGgies, an interest group for the Python language, now led by Wesley Chun and Danny Yoo.
Causes are often only real when they have a human face. Francis Glassborow is that person for me and why I am an ACCU member and founded ACCent.
Francis is English, a retired school master, a life-time member of the ACCU, former editor of the ACCU's C Vu magazine, and prodigious book reviewer. He is one of the main contributors to the 3000+ book reviews on the main ACCU site. He helped organized one of the world's best annual programming conferences in Oxford, England.
Obviously, he cares deeply about our profession. Welcome to ACCent.
I was contact early this month by Luby Aczel, a Volunteer Coordinator for the non-profit Northern California studio of Recording for the Blind and Dyslexic. They create and lend educational material on CD or four track cassette to individuals with learning or visual disabilities. They need volunteers to read the many technical and computer manuals for which they get requests. Please visit their web site at www.rfbd.org to find out more about them. You can also contact Luby Aczel, at 650-493-3717, ext. 13
The C++ Standard Library, A Tutorial and Reference by Nicolai M. Josuttis, Addison-Wesley, 1999, ISBN 0-201-37926-0, 799pp
Rating: Highly Recommended
Reading Level: Easy.
This book is for C++ programmers at all experience levels.
The stated goal of this book is to “describe the C++ standard library so that all (or almost all) your programming questions are answered before you think of the question”, and it succeeds at this. It provides a conceptual overview of the components of the library, describes the details needed to use the components (with many useful source examples), and points out traps and pitfalls and ways of avoiding these.
Space does not permit an extensive list of the topics covered, but as an example, auto_ptr is covered for 21 pages, including a good discussion of when not to use auto_ptr.
The technical writing is excellent, being both precise and easy to read. It achieves the difficult goal of being simultaneously readable as a tutorial and usable as a reference.
I was only able to find two minor errors (although a few more are listed on the author's web site), which is very impressive for a book of this size and complexity.
There is an extensive index. In practice, it was fairly easy to use the index to locate any topics of interest.
I am not aware of any other book that covers the subject with nearly this much breadth and depth.
I think that some of the most important changes during the C++ standardization process were to the standard library. This book is a great way for programmers to catch up on any of these changes that they may have missed.
Essential for any programmer serious about writing modern C++ code
— Wayne Vucenic
By Reg Charney and Ali Çehreli
Generally, looking at all the data we have, we have yet to see a turnaround in the employment picture in the Valley. Normally, the newer technologies spurt ahead after their introduction. This has not really been the case, as far as the Valley goes. We are currently tracking UML, .NET, Security, and Multimedia openings. In Figure #1, you can see that even with the money Microsoft is pouring into .NET, its adoption is slowing. In the Valley, there were only 5 openings for Windows XP device drivers. For Windows overall, there were only 39 openings while there were 7 Linux openings. Security, last year’s poster child for “hot” technologies is not doing as well as most of us would hope—this while we are getting inundated with SPAM and viruses, worms, Trojan horses, etc.