diff --git a/CppCoreGuidelines.md b/CppCoreGuidelines.md index 0e6e378..1a80a37 100644 --- a/CppCoreGuidelines.md +++ b/CppCoreGuidelines.md @@ -3378,7 +3378,7 @@ The standard library requires that all classes it deals with have destructors th None have succeeded to come up with a general scheme. This can be be a real practical problem: For example, what about a sockets that won't close? The writer of a destructor does not know why the destructor is called and cannot "refuse to act" by throwing an exception. -See discussion. +See discussion. To make the problem worse, many "close/release" operations are not retryable. If at all possible, consider failure to close/cleanup a fundamental design error and terminate. @@ -3726,7 +3726,7 @@ Setting a `Vector1` to empty after detecting an error is trivial. **Enforcement**: (Simple) A member initializer list should mention the members in the same order they are declared. -**See also**: [Discussion](#Sd order) +**See also**: [Discussion](#Sd-order) @@ -3865,7 +3865,7 @@ By providing the factory function `Create()`, we make construction (on the free **Note**: Conventional factory functions allocate on the free store, rather than on the stack or in an enclosing object. -**See also**: [Discussion](#Sd factory) +**See also**: [Discussion](#Sd-factory) @@ -11837,7 +11837,7 @@ Modernization can be much faster, simpler, and safer when supported with analysi This section contains follow-up material on rules and sets of rules. In particular, here we present further rationale, longer examples, and discussions of alternatives. -### Discussion: Define and initialize member variables in the order of member declaration +### Discussion: Define and initialize member variables in the order of member declaration Member variables are always initialized in the order they are declared in the class definition, so write them in that order in the constructor initialization list. Writing them in a different order just makes the code confusing because it won't run in the order you see, and that can make it hard to see order-dependent bugs. @@ -11867,7 +11867,7 @@ If the class definition and the constructor body are in separate files, the long ??? -### Discussion: Use a factory function if you need "virtual behavior" during initialization +### Discussion: Use a factory function if you need "virtual behavior" during initialization If your design wants virtual dispatch into a derived class from a base class constructor or destructor for functions like `f` and `g`, you need other techniques, such as a post-constructor -- a separate member function the caller must invoke to complete initialization, which can safely call `f` and `g` because in member functions virtual calls behave normally. Some techniques for this are shown in the References. Here's a non-exhaustive list of options: @@ -11923,7 +11923,7 @@ In summary, no post-construction technique is perfect. The worst techniques dodg -###Discussion: Make base class destructors public and virtual, or protected and nonvirtual +### Discussion: Make base class destructors public and virtual, or protected and nonvirtual Should destruction behave virtually? That is, should destruction through a pointer to a `base` class should be allowed? If yes, then `base`'s destructor must be public in order to be callable, and virtual otherwise calling it results in undefined behavior. Otherwise, it should be protected so that only derived classes can invoke it in their own destructors, and nonvirtual since it doesn't need to behave virtually virtual. @@ -12093,7 +12093,7 @@ When using exceptions as your error handling mechanism, always document this beh -## Define Copy, move, and destroy consistently +## Define Copy, move, and destroy consistently **Reason**: ??? @@ -12180,18 +12180,18 @@ In a class holding a reference, you likely need to write the copy constructor an Resource management rule summary: -* [Provide strong resource safety; that is, never leak anything that you think of as a resource](#Cr safety) -* [Never throw while holding a resource not owned by a handle](#Cr never) -* [A "raw" pointer or reference is never a resource handle](#Cr raw) -* [Never let a pointer outlive the object it points to](#Cr outlive) -* [Use templates to express containers (and other resource handles)](#Cr templates) -* [Return containers by value (relying on move for efficiency)](#Cr value return) -* [If a class is a resource handle, it needs a constructor, a destructor, and copy and/or move operations](#Cr handle) -* [If a class is a container, give it an initializer-list constructor](#Cr list) +* [Provide strong resource safety; that is, never leak anything that you think of as a resource](#Cr-safety) +* [Never throw while holding a resource not owned by a handle](#Cr-never) +* [A "raw" pointer or reference is never a resource handle](#Cr-raw) +* [Never let a pointer outlive the object it points to](#Cr-outlive) +* [Use templates to express containers (and other resource handles)](#Cr-templates) +* [Return containers by value (relying on move for efficiency)](#Cr-value-return) +* [If a class is a resource handle, it needs a constructor, a destructor, and copy and/or move operations](#Cr-handle) +* [If a class is a container, give it an initializer-list constructor](#Cr-list) -### Provide strong resource safety; that is, never leak anything that you think of as a resource +### Provide strong resource safety; that is, never leak anything that you think of as a resource **Reason**: Prevent leaks. Leaks can lead to performance degradation, mysterious error, system crashes, and security violations. @@ -12216,7 +12216,7 @@ This class is a resource handle. It manages the lifetime of the `T`s. To do so, **Enforcement**: The basic technique for preventing leaks is to have every resource owned by a resource handle with a suitable destructor. A checker can find "naked `new`s". Given a list of C-style allocation functions (e.g., `fopen()`), a checker can also find uses that are not managed by a resource handle. In general, "naked pointers" can be viewed with suspicion, flagged, and/or analyzed. A a complete list of resources cannot be generated without human input (the definition of "a resource" is necessarily too general), but a tool can be "parameterized" with a resource list. -### Never throw while holding a resource not owned by a handle +### Never throw while holding a resource not owned by a handle **Reason**: That would be a leak. @@ -12250,14 +12250,14 @@ For starters, we know about the standard-library containers, `string`, and smart The use of `array_view` and `string_view` should help a lot (they are not resource handles). -### A "raw" pointer or reference is never a resource handle +### A "raw" pointer or reference is never a resource handle **Reason** To be able to distinguish owners from views. **Note**: This is independent of how you "spell" pointer: `T*`, `T&`, `Ptr` and `Range` are not owners. -### Never let a pointer outlive the object it points to +### Never let a pointer outlive the object it points to **Reason**: To avoid extremely hard-to-find errors. Dereferencing such a pointer is undefined behavior and could lead to violations of the type system. @@ -12282,7 +12282,7 @@ The `string`s of `v` are destroyed upon exit from `bad()` and so is `v` itself. **Enforcement**: Most compilers already warn about simple cases and has the information to do more. Consider any pointer returned from a function suspect. Use containers, resource handles, and views (e.g., `array_view` known not to be resource handles) to lower the number of cases to be examined. For starters, consider every class with a destructor a resource handle. -### Use templates to express containers (and other resource handles) +### Use templates to express containers (and other resource handles) **Reason**: To provide statically type-safe manipulation of elements. @@ -12294,7 +12294,7 @@ The `string`s of `v` are destroyed upon exit from `bad()` and so is `v` itself. int sz; }; -### Return containers by value (relying on move for efficiency) +### Return containers by value (relying on move for efficiency) **Reason**: To simplify code and eliminate a need for explicit memory management. To bring an object into a surrounding scope, thereby extending its lifetime. @@ -12309,7 +12309,7 @@ The `string`s of `v` are destroyed upon exit from `bad()` and so is `v` itself. **Enforcement**: Check for pointers and references returned from functions and see if they are assigned to resource handles (e.g., to a `unique_ptr`). -### If a class is a resource handle, it needs a constructor, a destructor, and copy and/or move operations +### If a class is a resource handle, it needs a constructor, a destructor, and copy and/or move operations **Reason**: To provide complete control of the lifetime of the resource. To provide a coherent set of operations on the resource. @@ -12329,7 +12329,7 @@ Now `Named` has a default constructor, a destructor, and efficient copy and move **Enforcement**: In general, a tool cannot know if a class is a resource handle. However, if a class has some of [the default operations](???), it should have all, and if a class has a member that is a resource handle, it should be considered a resource handle. -### If a class is a container, give it an initializer-list constructor +### If a class is a container, give it an initializer-list constructor **Reason**: It is common to need an initial set of elements.