You might be surprised when you run the example—some C++ compilers have extended longjmp( ) to clean up objects on the stack. This behavior is not portable.
Visual Basic supports a limited form of resumptive exception handling with its ON ERROR facility.
In fact, you might want to always specify exception objects by const reference in exception handlers. It’s very rare to modify and rethrow an exception. We are not dogmatic about this practice however.
Only unambiguous, accessible base classes can catch derived exceptions. This rule minimizes the runtime overhead needed to validate exceptions. Remember that exceptions are checked at runtime, not at compile time, and therefore the extensive information available at compile time is not available during exception handling
For more detail on auto_ptr, see Herb Sutter’s article entitled, "Using auto_ptr Effectively" in the October 1999 issue of the C/C++ Users Journal, pp. 63–67.
If you’re interested in a more in-depth analysis of exception safety issues, the definitive reference is Herb Sutter’s Exceptional C++, Addison-Wesley, 2000.
The library function uncaught_exception( ) returns true in the middle of stack unwinding, so technically you can test uncaught_exception( ) for false and let an exception escape from a destructor. We’ve never seen a situation in which this constituted good design, however, so we only mention it in this footnote.
Some compilers do throw exceptions in these cases, but they usually provide a compiler option to disable this (unusual) behavior.
This depends, of course, on how much checking of return codes you would have to insert if you weren’t using exceptions.
Borland enables exceptions by default; to disable exceptions use the -x- compiler option. Microsoft disables support by default; to turn it on, use the -GX option. With both compilers use the -c option to compile only.
The GNU C++ compiler uses the zero-cost model by default. Metrowerks Code Warrior for C++ also has an option to use the zero-cost model.
Thanks to Scott Meyers and Josee Lajoie for their insights on the zero-cost model. You can find more information on how exceptions work in Josee’s excellent article, "Exception Handling: Behind the Scenes," C++ Gems, SIGS, 1996.
Among other things he invented Quicksort.
As quoted in Programming Language Pragmatics, by Michael L. Scott, Morgan-Kaufmann, 2000.
See his book, Object-Oriented Software Construction, Prentice-Hall, 1994.
This is still an assertion conceptually, but since we don’t want to halt execution, the assert( ) macro is not appropriate. Java 1.4, for example, throws an exception when an assertion fails.
There is a nice phrase to help remember this phenomenon: “Require no more; promise no less,” first coined in C++ FAQs, by Marshall Cline and Greg Lomow (Addison-Wesley, 1994). Since pre-conditions can weaken in derived classes, we say that they are contravariant, and, conversely, post-conditions are covariant (which explains why we mentioned the covariance of exception specifications in Chapter 1).
This section is based on Chuck’s article, “The Simplest Automated Unit Test Framework That Could Possibly Work”, C/C++ Users Journal, Sept. 2000.
A good book on this subject is Martin Fowler's Refactoring: Improving the Design of Existing Code (Addison-Wesley, 2000). See also www.refactoring.com. Refactoring is a crucial practice of Extreme Programming (XP).
Lightweight methodologies such as XP have “joined forces” in the Agile Alliance (see http://www.agilealliance.org/home).
Our Date class is also “internationalized”, in that it supports wide character sets. This is introduced at the end of the next chapter.
See http://sourceforge.net/projects/cppunit for more information.
“Runtime Type Identification”, discussed in chapter 9. Specifically, we use the name( ) member function of the typeinfo class. By the way, if you're using Microsoft Visual C++, you need to specify the compile option /GR. If you don't, you'll get an access violation at runtime.
In particular, we use stringizing (via the # operator) and the predefined macros __FILE__ and __LINE__. See the code later in the chapter.
Batch files and shell scripts work well for this, of course. The Suite class is a C++-based way of organizing related tests.
Our key technical reviewer, Pete Becker of Dinkumware. Ltd., brought to our attention that it is illegal to use macros to replace C++ keywords. His take on this technique was as follows: “"This is a dirty trick. Dirty tricks are sometimes necessary to figure out why code isn't working, so you may want to keep this in your toolbox, but don't ship any code with it." Caveat programmer :-).
Thanks to Reg Charney of the C++ Standards Committee for suggesting this trick.
Some of the material in this chapter was originally created by Nancy Nicolaisen.
It’s difficult to make reference-counting implementations thread safe. (See Herb Sutter, More Exceptional C++, pp. 104вЂ"14). See Chapter 10 for more on programming with multiple threads.
It as an abbreviation for “no position.”
Discussed in depth in Chapter 6.
To keep the exposition simple, this version does not handle nested tags, such as comments.
It is tempting to use mathematics here to factor out some of these calls to erase(В ), but since in some cases one of the operands is string::npos (the largest unsigned integer available), integer overflow occurs and wrecks the algorithm.
Alert: For the safety reasons mentioned, the C++ Standards Committee is considering a proposal to redefine string::operator[] to behave identically to string::at() for C++0x.
Your implementation can define all three template arguments here. Because the last two template parameters have default arguments, such a declaration is equivalent to what we show here.
Beware that some versions of Microsoft Word erroneously replace single quote characters with an extended ASCII character when you save a document as text, which of course causes a compile error. We have no idea why this happens. Just replace the character manually with an apostrophe.
POSIX, an IEEE standard, stands for “Portable Operating System Interface” and is a generalization of many of the low-level system calls found in UNIX systems.
The implementation and test files for FULLWRAP are available in the freely distributed source code for this book. See the preface for details.
Explained in depth in Chapter 5.
For this reason, we can write ios::failbit instead of ios_base::failbit to save typing.
It is customary to use operator void*(В ) in preference to operator bool(В ) because the implicit conversions from bool to int may cause surprises, should you errantly place a stream in a context where an integer conversion can be applied. The operator void*(В ) function will only implicitly be called in the body of a Boolean expression.
An integral type used to hold single-bit flags.
A more in-depth treatment of stream buffers and streams in general can be found in Langer & Kreft’s, Standard C++ IOStreams and Locales, Addison-Wesley, 1999.
For more information on machine epsilon and floating-point computation in general, see Chuck’s article, “The Standard C Library, Part 3”, C/C++ Users Journal, March 1995, also available at www.freshsources.com/1995006a.htm.
Before putting nl into a header file, make it an inline function (see Chapter 7).
Jerry Schwarz is the designer of iostreams.
See the Langer & Kreft book mentioned earlier for more detailed information.
See, for example, Dinkumware’s Abridged library at www.dinkumware.com. This library omits locale support. and exception support is optional.
Vandevoorde and Josuttis, C++ Templates: The Complete Guide, Addison-Wesley, 2003.
The C++ standards committee is considering relaxing the only-within-a-template rule for these disambiguation hints, and some compilers are allowing then in non-template code already.
See Stroustrup, The C++ Programming Language, 3rd Edition, Addison-Wesley, pp. 335-336.
Technically, comparing two pointers not inside the same array is undefined behavior, but compilers nowadays don’t complain about this. All the more reason to do it right.
We are indebted to Nathan Myers for this example.
Such as type information encoded in a decorated name.
C++ compilers can introduce names anywhere they want, however. Fortunately, most don’t declare names they don’t need.
If you’re interested in seeing the proposal, it’s Core Issue 352.
A reference to the British animated short feature The Wrong Trousers by Nick Park.
We discuss vector
Since the forwarding functions are inline, no code is generated at all!
Also called Koenig lookup, after Andrew Koenig, who first proposed the technique to the C++ standards committee. ADL applies universally, whether templates are involved or not.
In a talk given at The C++ Seminar, Portland, OR, September, 2001.
Another template idiom, mixin inheritance, is covered in Chapter 9.
The fact that char_traits<>::compare(В ) may call strcmp(В ) in one instance vs. wcscmp(В ) in another, for example, is immaterial to the point we make here: the function performed by compare(В ) is the same.
Modern C++ Design: Generic Programming and Design Patterns Applied, Addison-Wesley, 2001.
C++ Gems, edited by Stan Lippman, SIGS, 1996.
Floating-point values are not compile-time constants, and therefore cannot be used in compile-time arithmetic.
In 1966 BГ¶hm and Jacopini proved that any language supporting selection and repetition, along with the ability to use an arbitrary number of variables, is equivalent to a Turing machine, which can implement any algorithm.
Czarnecki and Eisenecker, Generative Programming: Methods, Tools, and Applications, Addison-Wesley, 2000, p. 417.
There is a much better to compute powers of integers, of course (viz., the Russian Peasant Algorithm), but that is beside the point here.
Modern C++ Design, pp. 23-26.
You actually are not allowed to pass object types (other than built-ins) to an ellipsis parameter specification, but since we are only asking for its size (a compile-time operation), the expression is never actually evaluated at runtime.
A reprint of Todd’s original article can be found in Lippman, C++ Gems, SIGS, 1996.
See his and Nico’s book, C++ Templates, book cited earlier.
Namely, Blitz++ (http://www.oonumerics.org/blitz/), the Matrix Template Library (http://www.osl.iu.edu/research/mtl/), and POOMA (http://www.acl.lanl.gov/pooma/).В
We mean “vector” in the mathematical sense, as a fixed-length, one-dimensional, numerical array.
Langer and Kreft, “C++ Expression Templates”, C/C++ Users Journal, March 2003. See also the article on expression templates by Thomas Becker in the June 2003 issue of the same journal, and which was the inspiration for the material in this section.
As explained earlier, you must explicitly instantiate a template only once per program.
Visit http://www.bdsoft.com/tools/stlfilt.html.
Or something that is callable as a function, as you’ll see shortly.
This is simply an English rendition of O(n log n), which is the mathematical way of saying that for large n, the number of comparisons grows in direct proportion to the function f(n) = n log n.
Unless you do something ungainly like use global variables.
Function objects are also called functors, after a mathematical concept with similar behavior.
All standard iterators define a number of nested types, including value_type, which represents the type the iterator refers to. See Chapter 7 for more detail.
If a compiler were to define string::empty with default arguments (which is allowed), then the expression &string::empty would define a pointer to a member function taking the total number of arguments. Since there is no way for the compiler to provide the extra defaults, there would be a “missing argument” error when an algorithm applied string::empty via mem_fun_ref.
STLPort, for instance, which comes with version 6 of Borland C++ Builder and is based on SGI STL.
The stable_sort(В ) algorithm uses mergesort, which is indeed stable, but tends to run slower than quicksort on average.
Iterators are discussed in more depth in the next chapter.
Algorithms can determine the type of an iterator by reading its tag, discussed in the next chapter.
We’re ignoring the copy constructor and assignment operator in this example, since they don’t apply.
Without violating any copyright laws, of course.
Visit http://www.dinkumware.com, http://www.sgi.com/tech/stl, or http://www.stlport.org.
The container adaptors, stack, queue, and priority_queue do not support iterators, since they do not behave as sequences from the user’s point of view.
It will only work for implementations of vector that uses a pointer (a T*) as the iterator type, like STLPort does.
These were actually created to abstract the “locale” facets away from iostreams, so that locale facets could operate on any sequence of characters, not only iostreams. Locales allow iostreams to easily handle culturally-different formatting (such as the representation of money) and are beyond the scope of this book.
You will need to provide a char_traits specialization for any other argument type.
We are indebted to Nathan Myers for explaining this.
This is another example coached by Nathan Myers.
For a detailed explanation of this oddity, see Items 6 and 29 in Scott Meyer’s Effective STL.
We revisit multi-threading issues in Chapter 11.
Chuck designed and provided the original reference implementations for bitset and also bitstring, the precursor to vector
They will likely appear in the next revision of Standard C++.
Available at http://www.sgi.com/tech/stl.
As we explained earlier, the vector
With Microsoft’s compilers you will have to enable RTTI; it’s disabled by default. The command-line option enable it is /GR.
Compilers typically insert a pointer to a class’s RTTI table inside of its virtual function table.
A dynamic_cast
Even more importantly, we don’t want undefined behavior. It is an error for a base class not to have a virtual destructor.
The actual layout is of course implementation specific.
But not detected as an error.В dynamic_cast, however can solve this problem. See the next chapter for details.
Compilers can add arbitrary padding, so the size of an object must be at least as large as the sum of its parts, but can be larger.
We use the term hierarchy because everyone else does, but the graph representing multiple inheritance relationships is in general a directed acyclic graph (DAG), also called a lattice, for obvious reasons.
The presence of these pointers explains why the size of b is much larger than the size of four integers.В This is (part of) the cost of virtual base classes. There is also VPTR overhead due to the virtual constructor.
Note that the virtual inheritance is crucial to this example. If Top were not a virtual base class, there would be multiple Top subobjects, and the ambiguity would remain. Dominance with multiple inheritance only comes into play with virtual base classes.
Jerry Schwarz, the author of IOStreams, has remarked to both of us on separate occasions that if he had it to do over again, he would probably remove MI from the design of IOStreams and use multiple stream buffers and conversion operators instead.
A phrase coined by Zack Urlocker.
Also known as the “Gang of Four” book (GoF). Conveniently, the examples are in C++.
The C++ standards states: “No translation unit shall contain more than one definition of any variable, function, class type, enumeration type or template… Every program shall contain exactly one definition of every non-inline function or object that is used in that program.”
This is known as Meyers’ Singleton, after its creator, Scott Meyers.
Andrei Alexandrescu develops a superior, policy-based solution to implementing the Singleton pattern in Modern C++ Design.
For more information, see the article “Once is Not Enough” by Hyslop and Sutter in the March 2003 issue of CUJ.
For up-to-date information, visit http://hillside.net/patterns.
James O. Coplien, Advanced C++ Programming Styles and Idioms, Addison-Wesley, 1992.
It differs from Java in that java.util.Observable.notifyObservers(В ) doesn't call clearChanged(В ) until after notifying all the observers
There is some similarity between inner classes and subroutine closures, which save the reference environment of a function call so it can be reproduced later.
Much of this chapter began as a translation from the Concurrency chapter in Thinking in Java, 3rd edition, Prentice Hall 2003.
This is an oversimplification. Sometimes even when it seems like an atomic operation should be safe, it may not be, so you must be very careful when deciding that you can get away without synchronization. Removing synchronization is often a sign of premature optimization вЂ" things that can cause you a lot of trouble without gaining much. Or anything.
This is in contrast to Java, where you must hold the lock in order to call notify() (Java’s version of signal()). Although Posix threads, on which the ZThread library is loosely based, do not require that you hold the lock in order to call signal() or broadcast(), it is often recommended.
At the time of this writing, Cygwin (www.cygwin.com) was undergoing much-needed changes and improvements to its threading support, but we were still unable to observe deadlocking behavior with this program under the available version of Cygwin. The program deadlocked quickly under, for example, Linux.