Effective C++ Notes

Chapter 1: From C to C++

  • Item 1: C++ is a federation of languages This means that C++ supports procedural, object-oriented, generic, functional, and meta-programming - five programming styles, which can be confusing. It is a comprehensive language.

  • Item 2: Prefer const, enum, inline to #define #define is not part of the language, but part of the preprocessor. const, enum, and inline allow the compiler to detect errors.

  • Item 3: Use const to restrict possible errors For example, return const reference objects to prevent users from modifying them. Use const member functions to prevent damage to classes.

  • Item 4: Make sure objects are initialized before use Mainly use initialization lists to initialize members or parent classes. Additionally, if a class uses global objects, it’s impossible to know when those objects are initialized. Therefore, use static variables inside the class (which also have only one copy).

Chapter 2: Constructors, Destructors, and Assignment Operators

  • Item 5: Know what functions the compiler silently generates The compiler will generate default member functions as needed, including default constructor, copy constructor, destructor, and copy assignment operator.

The default copy assignment operator may not be able to copy reference members.

  • Item 6: Use =delete to explicitly disallow auto-generated functions This can prevent a class from being copied, blocking copying.

  • Item 7: Declare virtual destructors for polymorphic base classes This is a basic function.

  • Item 8: Prevent exceptions from leaving destructors This can lead to incomplete memory release or cause multiple exceptions to be thrown.

  • Item 9: Never call virtual functions during construction or destruction This is also obvious - if a derived class constructor enters the base class constructor and calls a virtual function, the derived class’s virtual function isn’t ready yet.

  • Item 10: Have operator= return a reference to *this This allows for continuous assignment.

  • Item 11: Handle self-assignment in operator= It’s difficult to ensure your self-assignment code has no issues, and self-assignment is a time-wasting behavior.

  • Item 12: Copy all parts of an object when copying This is obvious. If you implement an assignment function, you must copy all contents.

Chapter 3: Resource Management

  • Item 13: Objects are the basic unit of resource management You need to be able to acquire resources and correctly release them. The key is to use shared_ptr to manage memory, which can automatically release held resources.

  • Item 14: Copying resource-managing objects Either prohibit copying, use shared_ptr members, perform deep copying, or make the copying process transfer the resource.

  • Item 15: Provide access to raw resources in resource-managing classes The world isn’t perfect, and many APIs require passing raw resource pointers. Using shared_ptr can interfere with how the object is used.

  • Item 16: Use delete[] for arrays allocated with new[] To avoid this error, you can use vector containers to operate, avoiding the need for new arrays.

  • Item 17: Store newed objects in smart pointers in standalone statements If an exception is thrown between creating a new object and passing it to a shared_ptr, it will lead to memory leaks.

Chapter 4: Designs and Declarations

  • Item 18: Make interfaces easy to use correctly Interfaces can sometimes be difficult to express clearly. For example, if you pass in three int values, you need to clearly remember what each one represents. What if the parameters are passed in the wrong order? The book mentions passing in specific objects and using explicit to constrain parameters. You could also build a date object and then specify members, which I think is a bit better. Additionally, interfaces should have reasonable parameter settings and reasonable return values (such as returning smart pointers instead of raw pointers to force proper usage).

  • Item 19: Designing a class is a major project Object creation, destruction, initialization and assignment, whether passing objects by value causes exceptions, what are the legal values for the new type. Have type conversion functions been written? What about operators? Which functions should be deleted?

  • Item 20: Prefer pass-by-reference-to-const to pass-by-value Passing by value brings the call of the object’s constructor, consuming time. Passing by reference is like passing a pointer.

  • Item 21: Don’t return a reference to a local object When returning an object created by a function, you cannot return a reference to that object. The compiler will make the correct optimization steps by itself.

  • Item 22: Declare data members private If declared public, deleting a variable will cause all programs to be rewritten. If declared private, deleting a variable will cause inherited class programs to be rewritten. So declare them as private.

  • Item 23: Prefer non-member non-friend functions to member functions If a method only calls a few other member functions, there’s no need to set it as a member function. Put it outside and wrap it with the same namespace.

  • Item 24: Declare non-member functions when type conversions should apply to all parameters This is because member functions may not work in some cases. For example, operator * can only support that type as the first parameter. It will fail when a built-in type is used as the first parameter.

  • Item 25: Consider support for a non-throwing swap Swap is a useful function. To implement an efficient swap, you need to design a swap member function to exchange with another object. Then design a non-member function in the namespace to call the above swap function. Finally, specialize std::swap to let the compiler choose your own swap.

Chapter 5: Implementations

  • Item 26: Postpone variable definitions as long as possible C++ cannot arbitrarily change the order of different lines, which means it’s better to define something only when it’s used. If all definitions are placed at the beginning, but the program returns right away, this would bring unnecessary construction and destruction processes.

  • Item 27: Minimize casting Although the four types of C++ type conversions can be used, they all bring bigger problems. Old-style type conversions should be used even less.

  • Item 28: Avoid returning handles to object internals Try to avoid returning pointers to internal data of objects outside the object, as this can cause big problems. The vector [] operator is such a case. This is a special case.

  • Item 29: Strive for exception-safe code C++ exceptions are the most difficult thing to handle, but you still need to ensure exceptions.

  • Item 30: Understand the ins and outs of inlining Inline is to make the compiler try to avoid stack expansion, not definitely. The 80-20 rule tells us that a program will only spend time on 20% of the code, so not all functions need to use inline.

  • Item 31: Minimize compilation dependencies: Separate definitions from declarations Two ways to handle - implementation classes and interface classes. Implementation classes use another class to proxy the functionality of the class. Interface classes use object-oriented methods to design the class as an interface.

Chapter 6: Inheritance and Object-Oriented Design

  • Item 32: Make sure public inheritance models “is-a” This means that derived classes can do everything base classes can do. But what derived classes can do, base classes may not be able to do.

  • Item 33: Avoid hiding inherited names If you declare another overloaded version of a parent class function in a derived class, it will also override the original version of the parent class, making it impossible to correctly link to the parent class function. You can use “using” to indicate the use of the parent class’s function space.

  • Item 34: Differentiate between inheritance of interface and inheritance of implementation Pure virtual functions only inherit the interface, virtual functions inherit the interface and default implementation, and non-virtual functions inherit the interface and forced implementation.

  • Item 35: Consider alternatives to virtual functions Other design patterns can be used to replace the implementation of virtual functions, such as function objects.

  • Item 36: Never redefine an inherited non-virtual function Otherwise, you won’t know which one is being called. Yes, I’m talking about destructors.

  • Item 37: Never redefine a function’s inherited default parameter value This is because default parameters are statically determined, not dynamically determined. The one you define may not be useful.

  • Item 38: Model “has-a” or “is-implemented-in-terms-of” through composition Public inheritance is an “is-a” relationship. Composition is a “has-a” relationship. For example, in the implementation of a set, inheriting from list would have some problems. Set should compose list.

  • Item 39: Use private inheritance judiciously The frequency of using private inheritance is lower than composition. There are two cases where this implementation is needed: first, when the derived class needs to access the protected members of the base class; second, when virtual functions need to be redefined (shouldn’t a middle class be designed in this case?).

  • Item 40: Use multiple inheritance judiciously Multiple inheritance is rarely used. It’s best not to include any members in virtual inheritance. This is because the initialization of members in virtual inheritance is done in the derived class.

Chapter 7: Templates and Generic Programming

  • Item 41: Understand implicit interfaces and compile-time polymorphism This is static polymorphism.

  • Item 42: Understand the two meanings of typename Typename appears not only in the template line of a template but also in template processing. When we use member variables or member types, the compiler doesn’t know which one is being used. By default, it uses member variables. Add typename to remind the compiler that it’s a member type.

  • Item 43: Know how to access names in templatized base classes This is because template classes can be specialized, and if specialized, some symbols may not exist. So you need to explicitly indicate symbols in the template class, such as using the this pointer or scope.

  • Item 44: Factor parameter-independent code out of templates When a template passes a non-type parameter, it generates multiple copies of code. There are some ways to avoid generating duplicate code, but they’re not as fast as the original.

  • Item 45: Use member function templates to accept all compatible types Classes can be templates, and member functions can also be templates.

  • Item 46: Define non-member functions inside templates when type conversions are desired Not only define it as a non-member function but also as a friend function.

  • Item 47: Use traits classes for information about types Traits use the properties of template programming and specialization to implement a traits class, through which you can get the data type you want in the generalized class.

  • Item 48: Be aware of template metaprogramming Metaprogramming refers to programming methods where results are known at compile time. For example, processing input at compile time. Similar to factorial, which is like the Hello World program of C++ metaprogramming.

Chapter 8: Customizing new and delete

  • Item 49: Understand the behavior of the new-handler It continuously tries to allocate memory. I’m curious if there will be a freeze if the new-handler keeps failing to allocate.

  • Item 50: Understand when it makes sense to replace new and delete It seems that the performance of new and delete is very high now. No need to replace them.

  • Item 51: Adhere to convention when writing new and delete Maintain compatibility when customizing new and delete.

  • Item 52: Write placement delete if you write placement new Placement delete will automatically run when placement new encounters an error.

Chapter 9: Modern C++11

  • Item 53: Pay attention to compiler warnings Don’t ignore warnings.

  • Item 54: Familiarize yourself with the TR1 standard libraries

  • Item 55: Familiarize yourself with Boost

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy