Learn Effective C++: 55 Specific Ways to Improve Your Programs and Designs with this Free PDF
Effective C++: 55 Specific Ways to Improve Your Programs and Designs
If you are a C++ programmer who wants to write better code, you should read Effective C++, a book by Scott Meyers that offers 55 specific guidelines for improving your programs and designs. Scott Meyers is one of the world's foremost experts on C++, and his book is distilled from his many years of experience as a consultant, trainer, and author. In this article, we will give you an overview of what this book can teach you, what's new in the third edition, how to use it effectively, and a summary of each guideline. We will also answer some frequently asked questions about the book at the end.
Effective C Third Edition 55 Specific Ways To Improve Your Programs And Designs Pdf Free
Why read this book?
C++ is a powerful and complex language that offers many features and possibilities for creating high-performance and flexible software. However, it also comes with many pitfalls and traps that can lead to bugs, inefficiencies, or poor design choices. To avoid these problems, you need to master not only the syntax and semantics of C++, but also the idioms and best practices that make it effective.
That's where Effective C++ comes in. This book is not a tutorial or a reference on C++, but a collection of practical advice that shows you how to use C++ in a more elegant, robust, and efficient way. Each guideline is based on real-world examples and explains not only what to do, but also why and how. By following these guidelines, you will learn how to write code that is more readable, maintainable, portable, reusable, and exception-safe. You will also learn how to avoid common mistakes and pitfalls that can cause subtle or serious errors.
Effective C++ is suitable for programmers of all levels, from beginners to experts. Whether you are new to C++, or have been using it for years, you will find something valuable in this book that will improve your skills and understanding of the language.
What's new in the third edition?
The third edition of Effective C++ was published in 2005, more than eight years after the second edition. During this time, C++ evolved significantly, with new standards (C++98 and C++03), new compilers, new libraries (such as STL and Boost), and new techniques (such as generic programming and template metaprogramming). To reflect these changes, Scott Meyers updated his book with more than half of the content being new or revised.
Some of the major changes and additions in the third edition are:
A new chapter on resource management, covering topics such as smart pointers, reference counting, garbage collection, RAII (Resource Acquisition Is Initialization), and copy-on-write.
A new chapter on templates and generic programming, covering topics such as template parameters, template specialization, traits classes, type deduction, template metaprogramming, and policy-based design.
A new chapter on customizing new and delete, covering topics such as placement new, class-specific memory management, memory pools, and overloading new and delete.
Revised guidelines on exception safety, inheritance, object-oriented design, and STL.
New guidelines on topics such as namespaces, casts, auto_ptr, enums, and typedefs.
More examples, explanations, references, and cross-references.
The third edition of Effective C++ is the most up-to-date and comprehensive guide to C++ best practices available today. It covers not only the core language features, but also the most important libraries and techniques that are widely used by C++ programmers.
How to use this book?
The book is organized around 55 specific guidelines, each of which describes a way to write better C++. Each guideline is backed by concrete examples that illustrate the problem and the solution. The guidelines are grouped into eight chapters, each focusing on a different aspect of C++ programming. The chapters are:
Accustoming Yourself to C++
Constructors, Destructors, and Assignment Operators
Resource Management
Designs and Declarations
Implementations
Inheritance and Object-Oriented Design
Templates and Generic Programming
Customizing new and delete
Miscellany
You can read the book from cover to cover, or you can use it as a reference and jump to the guidelines that interest you the most. Each guideline is self-contained and can be understood without reading the others. However, some guidelines may refer to or depend on other guidelines, in which case you will find cross-references to help you navigate the book. You will also find references to other books and articles that provide more details or alternative perspectives on the topics covered by the guidelines.
The book assumes that you have a basic knowledge of C++ syntax and semantics, as well as some familiarity with object-oriented programming. If you need a refresher on these topics, you can consult one of the many introductory books on C++ available in the market. The book also assumes that you have access to a modern C++ compiler that supports the C++98 or C++03 standard. If you are using an older or non-standard compiler, you may encounter some differences or incompatibilities with the code examples in the book.
The 55 guidelines
In this section, we will give you a brief summary of each guideline in the book, along with a short explanation of why it is important or useful. For more details and examples, you should refer to the book itself.
Accustoming Yourself to C++
This chapter covers some basic but essential topics that every C++ programmer should know and follow. These include:
Guideline 1: View C++ as a federation of languages. C++ is not a single language, but a combination of several sublanguages, each with its own rules and idioms. These sublanguages are: C, Object-Oriented C++, Template C++, and STL. You should learn how to use each sublanguage effectively and appropriately.
Guideline 2: Prefer consts, enums, and inlines to #defines. Using #defines for constants or macros can cause problems such as name collisions, type errors, or debugging difficulties. Using consts for constants, enums for enumerations, and inlines for functions can avoid these problems and offer more benefits such as type safety, scope control, or better performance.
Guideline 3: Use const whenever possible. Using const can help you write more correct and maintainable code by preventing accidental modifications of variables or objects. It can also enable compiler optimizations and improve performance. You should use const for variables, pointers, references, iterators, member functions, return types, parameters, and anything else that can be made constant.
are initialized before they're used. Uninitialized objects can cause undefined behavior or hard-to-find bugs. You should always initialize your objects before using them, either by using constructors, assignment operators, or initializer lists.
Guideline 5: Know what functions C++ silently writes and calls. C++ automatically generates some special member functions for your classes, such as the default constructor, the copy constructor, the copy assignment operator, and the destructor. You should know when these functions are generated, what they do, and how to prevent or customize them.
Guideline 6: Explicitly disallow the use of compiler-generated functions you do not want. Sometimes you may want to prevent some of the compiler-generated functions from being used, either because they are not meaningful or because they are dangerous. For example, you may want to prevent copying or assignment of some classes. You can do this by declaring these functions as private and not defining them, or by using a base class that does the same.
Guideline 7: Declare destructors virtual in polymorphic base classes. If you have a class hierarchy that uses polymorphism (i.e., virtual functions), you should make sure that the base class has a virtual destructor. This ensures that when you delete an object through a pointer to the base class, the correct destructor for the derived class is called. Otherwise, you may end up with memory leaks or undefined behavior.
Guideline 8: Prevent exceptions from leaving destructors. If an exception is thrown during the execution of a destructor, and it is not caught and handled within the destructor, the program will terminate abruptly. This can cause resource leaks or inconsistent states. To avoid this, you should make sure that your destructors do not throw exceptions, or that they catch and handle any exceptions that may occur.
Constructors, Destructors, and Assignment Operators
This chapter covers some topics related to the special member functions that are responsible for creating, destroying, and assigning objects. These include:
Guideline 9: Never call virtual functions during construction or destruction. Calling virtual functions during construction or destruction can lead to unexpected results, because the dynamic type of the object may not match the static type of the pointer or reference. The virtual function that is called is the one defined by the constructor or destructor's class, not by any derived class. To avoid this problem, you should avoid calling virtual functions in constructors or destructors, or make them non-virtual if they are meant to be called from there.
Guideline 10: Have assignment operators return a reference to *this. Returning a reference to *this from an assignment operator allows you to chain assignments together, such as a = b = c. It also makes your assignment operators consistent with the built-in types and with STL containers. You should always return a reference to *this from your assignment operators, unless you have a good reason not to.
Guideline 11: Handle assignment to self in operator=. When you write an assignment operator for your class, you should make sure that it works correctly when the left-hand side and the right-hand side are the same object. This can happen when you assign an object to itself, or when you assign two objects that refer to the same underlying data. To handle this case, you can use one of these techniques: check for self-assignment using identity test (this == &rhs), copy the right-hand side object to a local variable before modifying the left-hand side object, or use the copy-and-swap idiom.
Guideline 12: Copy all parts of an object. When you write a copy constructor or a copy assignment operator for your class, you should make sure that it copies all parts of the object, including any base class subobjects and any member variables. Otherwise, you may end up with incomplete or inconsistent copies that can cause bugs or undefined behavior. You can use member initialization lists in copy constructors and copy assignment operators in derived classes to invoke copy constructors and copy assignment operators in base classes.
Resource Management
This chapter covers some topics related to managing resources such as memory, files, sockets, locks, etc. These include:
Guideline 13: Use objects to manage resources. Resources are anything that must be acquired before use and released after use, such as memory, files, sockets, locks, etc. Managing resources manually can be error-prone and tedious, especially in the presence of exceptions. A better way to manage resources is to use objects that acquire resources in their constructors and release them in their destructors. This technique is known as RAII (Resource Acquisition Is Initialization) or SBRM (Scope-Bound Resource Management). You should use RAII objects to manage your resources, either by using existing classes such as std::vector, std::string, std::unique_ptr, std::lock_guard, etc., or by writing your own classes that follow the RAII principle.
Guideline 14: Think carefully about copying behavior in resource-managing classes. When you write a class that manages a resource, you should decide how you want it to behave when it is copied or assigned. There are three common options: disallow copying and assignment (e.g. std::unique_ptr), perform deep copying and assignment (e.g. std::string), or perform reference counting and copy-on-write (e.g. std::shared_ptr). Each option has its advantages and disadvantages, and you should choose the one that best suits your needs and expectations.
Guideline 15: Provide access to raw resources in resource-managing classes. Sometimes you may need to access the raw resource (such as a pointer, a file handle, a socket descriptor, etc.) that is managed by a RAII object. For example, you may need to pass it to a legacy API that expects a raw resource, or you may need to perform some low-level operations on it. To enable this, you should provide a way to access the raw resource in your resource-managing class, either by using an explicit conversion function (e.g. std::unique_ptr::get) or by using an implicit conversion operator (e.g. std::shared_ptr::operator*). However, you should also make sure that the user of your class does not misuse the raw resource or violate the ownership semantics of your class.
Guideline 16: Use the same form in corresponding uses of new and delete. When you allocate memory using new, you should deallocate it using delete. When you allocate memory using new[], you should deallocate it using delete[]. Mixing these forms can cause undefined behavior or memory leaks. You should always use the same form in corresponding uses of new and delete, and avoid using new[] and delete[] unless you really need them.
Guideline 17: Store newed objects in smart pointers in standalone statements. When you allocate an object using new, you should store it in a smart pointer (such as std::unique_ptr, std::shared_ptr, or std::auto_ptr) that will automatically delete it when it goes out of scope or when it is no longer needed. This way, you can avoid memory leaks or dangling pointers. However, you should also make sure that you store the newed object in a smart pointer in a standalone statement, not as part of a larger expression. This is because C++ does not guarantee the order of evaluation of subexpressions, and if an exception is thrown during the evaluation of a subexpression, the newed object may not be stored in the smart pointer and may leak memory. You should always store newed objects in smart pointers in standalone statements, and avoid passing them directly as arguments to functions or constructors.
(To be continued...)
71b2f0854b