📄 e.htm
字号:
Effective C++, 2EDedicationFor Nancy, without whom nothing would be much worth doing. Back to DedicationContinue to AcknowledgmentsPrefaceThis book is a direct outgrowth of my experiences teaching C++ to professional programmers. I've found that most students, after a week of intensive instruction, feel comfortable with the basic constructs of the language, but they tend to be less sanguine about their ability to put the constructs together in an effective manner. Thus began my attempt to formulate short, specific, easy-to-remember guidelines for effective software development in C++: a summary of the things experienced C++ programmers almost always do or almost always avoid doing.I was originally interested in rules that could be enforced by some kind of lint-like program. To that end, I led research into the development of tools to examine C++ source code for violations of user-specified conditions.1 Unfortunately, the research ended before a complete prototype could be developed. Fortunately, several commercial C++-checking products are now available. (You'll find an overview of such products in the article on static analysis tools by me and Martin Klaus.)Though my initial interest was in programming rules that could be automatically enforced, I soon realized the limitations of that approach. The majority of guidelines used by good C++ programmers are too difficult to formalize or have too many important exceptions to be blindly enforced by a program. I was thus led to the notion of something less precise than a computer program, but still more focused and to-the-point than a general C++ textbook. The result you now hold in your hands: a book containing 50 specific suggestions on how to improve your C++ programs and designs.In this book, you'll find advice on what you should do, and why, and what you should not do, and why not. Fundamentally, of course, the whys are more important than the whats, but it's a lot more convenient to refer to a list of guidelines than to memorize a textbook or two.Unlike most books on C++, my presentation here is not organized around particular language features. That is, I don't talk about constructors in one place, about virtual functions in another, about inheritance in a third, etc. Instead, each discussion in the book is tailored to the guideline it accompanies, and my coverage of the various aspects of a particular language feature may be dispersed throughout the book.The advantage of this approach is that it better reflects the complexity of the software systems for which C++ is often chosen, systems in which understanding individual language features is not enough. For example, experienced C++ developers know that understanding inline functions and understanding virtual destructors does not necessarily mean you understand inline virtual destructors. Such battle-scarred developers recognize that comprehending the interactions between the features in C++ is of the greatest possible importance in using the language effectively. The organization of this book reflects that fundamental truth.The disadvantage of this design is that you may have to look in more than one place to find everything I have to say about a particular C++ construct. To minimize the inconvenience of this approach, I have sprinkled cross-references liberally throughout the text, and a comprehensive index is provided at the end of the book.In preparing this second edition, my ambition to improve the book has been tempered by fear. Tens of thousands of programmers embraced the first edition of Effective C++, and I didn't want to destroy whatever characteristics attracted them to it. However, in the six years since I wrote the book, C++ has changed, the C++ library has changed (see Item 49), my understanding of C++ has changed, and accepted usage of C++ has changed. That's a lot of change, and it was important to me that the technical material in Effective C++ be revised to reflect those changes. I'd done what I could by updating individual pages between printings, but books and software are frighteningly similar there comes a time when localized enhancements fail to suffice, and the only recourse is a system-wide rewrite. This book is the result of that rewrite: Effective C++, Version 2.0.Those familiar with the first edition may be interested to know that every Item in the book has been reworked. I believe the overall structure of the book remains sound, however, so little there has changed. Of the 50 original Items, I retained 48, though I tinkered with the wording of a few Item titles (in addition to revising the accompanying discussions). The retired Items (i.e., those replaced with completely new material) are numbers 32 and 49, though much of the information that used to be in Item 32 somehow found its way into the revamped Item 1. I swapped the order of Items 41 and 42, because that made it easier to present the revised material they contain. Finally, I reversed the direction of my inheritance arrows. They now follow the almost-universal convention of pointing from derived classes to base classes. This is the same convention I followed in my 1996 book, More Effective C++.The set of guidelines in this book is far from exhaustive, but coming up with good rules ones that are applicable to almost all applications almost all the time is harder than it looks. Perhaps you know of additional guidelines, of more ways in which to program effectively in C++. If so, I would be delighted to hear about them.On the other hand, you may feel that some of the Items in this book are inappropriate as general advice; that there is a better way to accomplish a task examined in the book; or that one or more of the technical discussions is unclear, incomplete, or misleading. I encourage you to let me know about these things, too.Donald Knuth has a long history of offering a small reward to people who notify him of errors in his books. The quest for a perfect book is laudable in any case, but in view of the number of bug-ridden C++ books that have been rushed to market, I feel especially strongly compelled to follow Knuth's example. Therefore, for each error in this book that is reported to me be it technical, grammatical, typographical, or otherwise I will, in future printings, gladly add to the acknowledgments the name of the first person to bring that error to my attention.Send your suggested guidelines, your comments, your criticisms, and sigh your bug reports to: Scott Meyers c/o Publisher, Corporate and Professional Publishing Addison Wesley Longman, Inc. 1 Jacob Way Reading, MA 01867 U. S. A.Alternatively, you may send electronic mail to ec++@awl.com.I maintain a list of changes to this book since its first printing, including bug-fixes, clarifications, and technical updates. This list is available at the Effective C++ World Wide Web site. If you would like a copy of this list, but you lack access to the World Wide Web, please send a request to one of the addresses above, and I will see that the list is sent to you. Scott Douglas MeyersStafford, OregonJuly 1997 Back to PrefaceContinue to IntroductionAcknowledgmentsSome three decades have elapsed since Kathy Reed taught me what a computer was and how to program one, so I suppose this is really all her fault. In 1989, Donald French asked me to develop C++ training materials for the Institute for Advanced Professional Studies, so perhaps he should shoulder some blame. The students in my class at Stratus Computer the week of June 3, 1991, were not the first to suggest I write a book summarizing the pearls of alleged wisdom that tumble forth when I teach, but they were the ones who finally convinced me to do it, so they bear some of the responsibility. I'm grateful to them all.Many of the Items and examples in this book have no particular source, at least not one I can remember. Instead, they grew out of a combination of my own experiences using and teaching C++, those of my colleagues, and opinions expressed by contributors to the Usenet C++ newsgroups. Many examples that are now standard in the C++ teaching community notably strings can be traced back to the initial edition of Bjarne Stroustrup's The C++ Programming Language (Addison-Wesley, 1986). Several of the Items found here (e.g., Item 17) can also be found in that seminal work.Item 8 includes an implementation idea from Steve Clamage's May 1993 C++ Report article, "Implementing new and delete." Item 9 was motivated by commentary in The Annotated C++ Reference Manual (see Item 50), and Items 10 and 13 were suggested by John Shewchuk. The implementation of operator new in Item 10 is based on presentations in the second edition of Stroustrup's The C++ Programming Language (Addison-Wesley, 1991) and Jim Coplien's Advanced C++: Programming Styles and Idioms (Addison-Wesley, 1992). Dietmar Khl pointed out the undefined behavior I describe in Item 14. Doug Lea provided the aliasing examples at the end of Item 17. The idea of using 0L for NULL in Item 25 came from Jack Reeves's March 1996 C++ Report article, "Coping with Exceptions." Several members of various Usenet C++ newsgroups helped refine that Item's class for implementing NULL-based pointer conversions via member templates. A newsgroup posting by Steve Clamage tempered my enthusiasm for references to functions in Item 28. Item 33 incorporates observations from Tom Cargill's C++ Programming Style (Addison-Wesley, 1992), Martin Carroll's and Margaret Ellis's Designing and Coding Reusable C++ (Addison-Wesley, 1995), Taligent's Guide to Designing Programs (Addison-Wesley, 1994), Rob Murray's C++ Strategies and Tactics (Addison-Wesley, 1993), as well as information from publications and newsgroup postings by Steve Clamage. The material in Item 34 benefited from my discussions with John Lakos and from reading his book, Large-Scale C++ Software Design (Addison-Wesley, 1996). The envelope/letter terminology in that Item comes from Jim Coplien's Advanced C++: Programming Styles and Idioms; John Carolan coined the delightful term, "Cheshire Cat class." The rectangle/square example of Item 35 is taken from Robert Martin's March 1996 C++ Report column, "The Liskov Substitution Principle." A long-ago comp.lang.c++ posting by Mark Linton set me straight in my thinking about grasshoppers and crickets in Item 43. My traits examples in Item 49 are taken from Nathan Myers's June 1995 C++ Report article, "A New and Useful Template Technique: Traits," and Pete Becker's "C/C++ Q&A" column in the November 1996 C/C++ User's Journal; my summary of C++'s internationalization support is based on a pre-publication book draft by Angelika Langer and Klaus Kreft. Of course, "Hello world" comes from The C Programming Language by Brian Kernighan and Dennis Ritchie (Prentice-Hall, first publish in 1978).Many readers of the first edition sent suggestions I was unable to incorporate in that version of the book, but that I've adopted in one form or another for this new edition. Others took advantage of Usenet C++ newsgroups to post insightful remarks about the material in the book. I'm grateful to each of the following individuals, and I've noted where I took advantage of their ideas: Mike Kaelbling and Julio Kuplinsky (Introduction); a person my notes identify only as "a guy at Claris"2 (Item 5); Joel Regen and Chris Treichel (Item 7); Tom Cargill, Larry Gajdos, Doug Morgan, and Uwe Steinmller (Item 10); Roger Scott and Steve Burkett (Item 12); David Papurt (Item 13); Alexander Gootman (Item 14); David Bern (Item 16); Tom Cargill, Tom Chappell, Dan Franklin, and Jerry Liebelson (Item 17); John "Eljay" Love-Jensen (Item 19); Eric Nagler (Item 22); Roger Eastman, Doug Moore, and Aaron Naiman (Item 23); Dat Thuc Nguyen (Item 25); Tony Hansen, Natraj Kini, and Roger Scott (Item 33); John Harrington, Read Fleming, and Dave Smallberg (Item 34); Johan Bengtsson (Item 36); Rene Rodoni (Item 39); Paul Blankenbaker and Mark Somer (Item 40); Tom Cargill and John Lakos (Item 41); Frieder Knauss and Roger Scott (Item 42); David Braunegg, Steve Clamage, and Dawn Koffman (Item 45); Tom Cargill (Item 46); Wesley Munsil (Item 47); Randy Mangoba (most class definitions); and John "Eljay" Love-Jensen (many places where I use type double).Partial and/or complete drafts of the manuscript for the first edition were reviewed by Tom Cargill, Glenn Carroll, Tony Davis, Brian Kernighan, Jak Kirman, Doug Lea, Moises Lejter, Eugene Santos, Jr., John Shewchuk, John Stasko, Bjarne Stroustrup, Barbara Tilly, and Nancy L. Urbano. In addition, I received suggestions for improvements that I was able to incorporate in later printings from the following alert readers, whom I've listed in the order in which I received their reports: Nancy L. Urbano, Chris Treichel, David Corbin, Paul Gibson, Steve Vinoski, Tom Cargill, Neil Rhodes, David Bern, Russ Williams, Robert Brazile, Doug Morgan, Uwe Steinmller, Mark Somer, Doug Moore, Dave Smallberg, Seth Meltzer, Oleg Shteynbuk, David Papurt, Tony Hansen, Peter McCluskey, Stefan Kuhlins, David Braunegg, Paul Chisholm, Adam Zell, Clovis Tondo, Mike Kaelbling, Natraj Kini, Lars Nyman, Greg Lutz, Tim Johnson, John Lakos, Roger Scott, Scott Frohman, Alan Rooks, Robert Poor, Eric Nagler, Antoine Trux, Cade Roux, Chandrika Gokul, Randy Mangoba, and Glenn Teitelbaum. Each of these people was instrumental in improving the book you now hold.Drafts of the second edition were reviewed by Derek Bosch, Tim Johnson, Brian Kernighan, Junichi Kimura, Scott Lewandowski, Laura Michaels, Dave Smallberg, Clovis Tondo, Chris Van Wyk, and Oleg Zabluda. I am grateful to all these people, but especially to Tim Johnson, whose detailed review influenced the final manuscript in dozens of ways. I am also grateful to Jill Huchital and Steve Reiss for their assistance in finding good reviewers, a task of crucial importance and increasing difficulty. Dawn Koffman and Dave Smallberg suggested improvements to the C++ training materials derived from my books, and many of their ideas have found their way into this revision. Finally, I received comments from the following readers of earlier printings of this book, and I've modified this current printing to take their suggestions into account: Daniel Steinberg, Arunprasad Marathe, Doug Stapp, Robert Hall, Cheryl Ferguson, Gary Bartlett, Michael Tamm, Kendall Beaman, Eric Nagler, Max Hailperin, Joe Gottman, Richard Weeks, Valentin Bonnard, Jun He, Tim King, Don Maier, Ted Hill, Mark Harrison, Michael Rubenstein, Mark Rodgers, David Goh, Brenton Cooper, and Andy Thomas-Cramer.Evi Nemeth (with the cooperation of Addison-Wesley, the USENIX Association, and The Internet Engineering Task Force) has agreed to see to it that leftover copies of the first edition are delivered to computer science laboratories at universities in Eastern Europe; these universities would otherwise find it difficult to acquire such books. Evi voluntarily performs this service for several authors and publishers, and I'm happy to be able to help in some small way. If you'd like more information on this program, contact Evi.Sometimes it seems that the players in publishing change nearly as frequently as the trends in programming, so I'm pleased that my editor, John Wait, my marketing director, Kim Dawley, and my production director, Marty Rabinowitz, continue to play the roles they did in those innocent days of 1991 when I first started this whole authoring thing. Sarah Weaver was my project manager for this book, Rosemary Simpson provided advice on indexing, and Lana Langlois acted as my primary contact and all-around bercoordinator at Addison-Wesley until she left for greener or at least different pastures. I thank them and their colleagues for helping with the thousand tasks that separate simple writing from actual publishing.Kathy Wright had nothing to do with the book, but she'd like to be acknowledged.For the first edition, I am grateful for the enthusiastic and unflagging encouragement provided by my wife, Nancy L. Urbano, and by my family and hers. Although writing a book was the last thing I was supposed to be doing, and doing so reduced my free time from merely little to effectively none, they made it clear that the effort was worth it if, in the end, the result was an author in the family.That author has been in the family six years now, yet Nancy continues to tolerate my hours, put up with my technochatter, and encourage my writing. She also has a knack for knowing just the right word when I can't think of it. The Nancyless life is not worth living.Our dog, Persephone, never lets me confuse my priorities. Deadline or no deadline, the time for a walk is always now. Back to AcknowledgmentsContinue to Shifting from C to C++IntroductionLearning the fundamentals of a programming language is one thing; learning how to design and implement effective programs in that language is something else entirely. This is especially true of C++, a language boasting an uncommon range of power and expressiveness. Built atop a full-featured conventional language (C), it also offers a wide range of object-oriented features, as well as support for templates and exceptions.Properly used, C++ can be a joy to work with. An enormous variety of designs, both object-oriented and conventional, can be expressed directly and implemented efficiently. You can define new data types that are all but indistinguishable from their built-in counterparts, yet are substantially more flexible. A judiciously chosen and carefully crafted set of classes one that automatically handles memory management, aliasing, initialization and clean-up, type conversions, and all the other conundrums that are the bane of software developers can make application programming easy, intuitive, efficient, and nearly error-free. It isn't unduly difficult to write effective C++ programs, if you know how to do it.Used without discipline, C++ can lead to code that is incomprehensible, unmaintainable, inextensible, inefficient, and just plain wrong.The trick is to discover those aspects of C++ that are likely to trip you up and to learn how to avoid them. That is the purpose of this book. I assume you already know C++ as a language and that you have some experience in its use. What I provide here is a guide to using the language effectively, so that your software is comprehensible, maintainable, extensible, efficient, and likely to behave as you expect.The advice I proffer falls into two broad categories: general design strategies, and the nuts and bolts of specific language features.The design discussions concentrate on how to choose between different approaches to accomplishing something in C++. How do you choose between inheritance and templates? Between templates and generic pointers? Between public and private inheritance? Between private inheritance and layering? Between function overloading and parameter defaulting? Between virtual and nonvirtual functions? Between pass-by-value and pass-by-reference? It is important to get these decisions right at the outset, because an incorrect choice may not become apparent until much later in the development process, at which point its rectification is often difficult, time-consuming, demoralizing, and expensive.Even when you know exactly what you want to do, getting things just right can be tricky. What's the proper return type for the assignment operator? How should operator new behave when it can't find enough memory? When should a destructor be virtual? How should you write a member initialization list? It's crucial to sweat details like these, because failure to do so almost always leads to unexpected, possibly mystifying, program behavior. More importantly, the aberrant behavior may not be immediately apparent, giving rise to the specter of code that passes through quality control while still harboring a variety of undetected bugs ticking time-bombs just waiting to go off.This is not a book that must be read cover to cover to make any sense. You need not even read it front to back. The material is broken down into 50 Items, each of which stands more or less on its own. Frequently, however, one Item will refer to others, so one way to read the book is to start with a particular Item of interest and then follow the references to see where they lead you.The Items are grouped into general topic areas, so if you are interested in discussions related to a particular issue, such as memory management or object-oriented design, you can start with the relevant section and either read straight through or start jumping around from there. You will find, however, that all of the material in this book is pretty fundamental to effective C++ programming, so almost everything is eventually related to everything else in one way or another.This is not a reference book for C++, nor is it a way for you to learn the language from scratch. For example, I'm eager to tell you all about the gotchas in writing your own operator new (see Items 7-10), but I assume you can go elsewhere to discover that that function must return a void* and its first argument must be of type size_t. There are a number of introductory books on C++ that contain information such as that.The purpose of this book is to highlight those aspects of C++ programming that are usually treated superficially (if at all). Other books describe the different parts of the language. This book tells you how to combine those parts so you end up with effective programs. Other books tell you how to get your programs to compile. This book tells you how to avoid problems that compilers won't tell you about.Like most languages, C++ has a rich folklore that is usually passed from programmer to programmer as part of the language's grand oral tradition. This book is my attempt to record some of that accumulated wisdom in a more accessible form.At the same time, this book limits itself to legitimate, portable, C++. Only language features in the ISO/ANSI language standard (see Item M35) have been used here. In this book, portability is a key concern, so if you're looking for implementation-dependent hacks and kludges, this is not the place to find them.Alas, C++ as described by the standard is sometimes different from the C++ supported by your friendly neighborhood compiler vendors. As a result, when I point out places where relatively new language features are useful, I also show you how to produce effective software in their absence. After all, it would be foolish to labor in ignorance of what the future is sure to bring, but by the same token, you can't just put your life on hold until the latest, greatest, be-all-and-end-all C++ compilers appear on your computer. You've got to work with the tools available to you, and this book helps you do just that.Notice that I refer to compilers plural. Different compilers implement varying approximations to the standard, so I encourage you to develop your code under at least two compilers. Doing so will help you avoid inadvertent dependence on one vendor's proprietary language extension or its misinterpretation of the standard. It will also help keep you away from the bleeding edge of compiler technology, i.e., from new features supported by only one vendor. Such features are often poorly implemented (buggy or slow frequently both), and upon their introduction, the C++ community lacks experience to advise you in their proper application. Blazing trails can be exciting, but when your goal is producing reliable code, it's often best to let others do the bushwhacking for you.One thing you will not find in this book is the C++ Gospel, the One True Path to perfect C++ software. Each of the 50 Items in this book provides guidance on how to come up with better designs, how to avoid common problems, or how to achieve greater efficiency, but none of the Items is universally applicable. Software design and implementation is a complex task, one invariably colored by the constraints of the hardware, the operating system, and the application, so the best I can do is provide guidelines for creating better programs.If you follow all the guidelines all the time, you are unlikely to fall into the most common traps surrounding C++, but guidelines, by their very nature, have exceptions. That's why each Item has an explanation. The explanations are the most important part of the book. Only by understanding the rationale behind an Item can you reasonably determine whether it applies to the software you are developing and to the unique constraints under which you toil.The best use of this book, then, is to gain insight into how C++ behaves, why it behaves that way, and how to use its behavior to your advantage. Blind application of the Items in this book is clearly inappropriate, but at the same time, you probably shouldn't violate any of the guidelines without having a good reason for doing so.There's no point in getting hung up on terminology in a book like this; that form of sport is best left to language lawyers. However, there is a small C++ vocabulary that everybody should understand. The following terms crop up often enough that it is worth making sure we agree on what they mean.A declaration tells compilers about the name and type of an object, function, class, or template, but it omits certain details. These are declarations: extern int x; // object declarationint numDigits(int number); // function declarationclass Clock; // class declarationtemplate<class T>class SmartPointer; // template declarationA definition, on the other hand, provides compilers with the details. For an object, the definition is where compilers allocate memory for the object. For a function or a function template, the definition provides the code body. For a class or a class template, the definition lists the members of the class or template: int x; // object definitionint numDigits(int number) // function definition{ // (this function returns int digitsSoFar = 1; // the number of digits in // its parameter) if (number < 0) { number = -number; ++digitsSoFar; } while (number /= 10) ++digitsSoFar; return digitsSoFar;}class Clock { // class definitionpublic: Clock(); ~Clock(); int hour() const; int minute() const; int second() const; ...};template<class T>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -