mirror of
https://github.com/isocpp/CppCoreGuidelines.git
synced 2024-03-22 13:30:58 +08:00
commit
f6407cf235
|
@ -259,7 +259,6 @@ Tools that implement these rules shall respect the following syntax to explicitl
|
|||
where "tag" is the anchor name of the item where the Enforcement rule appears (e.g., for C.134 it is "Rh-public"), the
|
||||
name of a profile group-of-rules ("type", "bounds", or "lifetime"), or a specific rule in a profile ("type.4", or "bounds.2").
|
||||
|
||||
|
||||
## <a name="SS-struct"></a>In.struct: The structure of this document
|
||||
|
||||
Each rule (guideline, suggestion) can have several parts:
|
||||
|
@ -941,8 +940,6 @@ You can't have a data race on a constant.
|
|||
|
||||
See [Con: Constants and Immutability](#S-const)
|
||||
|
||||
|
||||
|
||||
# <a name="S-interfaces"></a>I: Interfaces
|
||||
|
||||
An interface is a contract between two parts of a program. Precisely stating what is expected of a supplier of a service and a user of that service is essential.
|
||||
|
@ -1062,7 +1059,7 @@ Every pointer or reference to mutable data is a potential data race.
|
|||
|
||||
You cannot have a race condition on immutable data.
|
||||
|
||||
**Reference**: See the [rules for calling functions](#SS-call).
|
||||
**References**: See the [rules for calling functions](#SS-call).
|
||||
|
||||
##### Enforcement
|
||||
|
||||
|
@ -1229,7 +1226,7 @@ Some preconditions can be expressed as assertions. For example:
|
|||
|
||||
Ideally, that `Expects(x >= 0)` should be part of the interface of `sqrt()` but that's not easily done. For now, we place it in the definition (function body).
|
||||
|
||||
**Reference**: `Expects()` is described in [GSL](#S-gsl).
|
||||
**References**: `Expects()` is described in [GSL](#S-gsl).
|
||||
|
||||
##### Note
|
||||
|
||||
|
@ -1605,7 +1602,7 @@ Consider:
|
|||
// ...
|
||||
draw(arr, 10);
|
||||
|
||||
Passing `10` as the `n` argument may be a mistake: the most common convention is to assume [`0`:`n`) but that is nowhere stated. Worse is that the call of `draw()` compiled at all: there was an implicit conversion from array to pointer (array decay) and then another implicit conversion from `Circle` to `Shape`. There is no way that `draw()` can safely iterate through that array: it has no way of knowing the size of the elements.
|
||||
Passing `10` as the `n` argument may be a mistake: the most common convention is to assume \[`0`:`n`) but that is nowhere stated. Worse is that the call of `draw()` compiled at all: there was an implicit conversion from array to pointer (array decay) and then another implicit conversion from `Circle` to `Shape`. There is no way that `draw()` can safely iterate through that array: it has no way of knowing the size of the elements.
|
||||
|
||||
**Alternative**: Use a support class that ensures that the number of elements is correct and prevents dangerous implicit conversions. For example:
|
||||
|
||||
|
@ -1628,7 +1625,6 @@ But when doing so, use `string_span` from the [GSL](#GSL) to prevent range error
|
|||
* (Simple) ((Bounds)) Warn for any expression that would rely on implicit conversion of an array type to a pointer type. Allow exception for zstring/czstring pointer types.
|
||||
* (Simple) ((Bounds)) Warn for any arithmetic operation on an expression of pointer type that results in a value of pointer type. Allow exception for zstring/czstring pointer types.
|
||||
|
||||
|
||||
### <a name="Ri-global-init"></a>I.22: Avoid complex initialization of global objects
|
||||
|
||||
##### Reason
|
||||
|
@ -2288,7 +2284,6 @@ Not possible.
|
|||
|
||||
There are a variety of ways to pass parameters to a function and to return values.
|
||||
|
||||
|
||||
### <a name="Rf-conventional"></a>F.15: Prefer simple and conventional ways of passing information
|
||||
|
||||
##### Reason
|
||||
|
@ -2302,8 +2297,6 @@ The following tables summarize the advice in the following Guidelines, F.16-21.
|
|||
|
||||
![Advanced parameter passing table](./param-passing-advanced.png "Advanced parameter passing")
|
||||
|
||||
|
||||
|
||||
### <a name="Rf-in"></a>F.16: For "in" parameters, pass cheaply-copied types by value and others by reference to `const`
|
||||
|
||||
##### Reason
|
||||
|
@ -2327,7 +2320,7 @@ For advanced uses (only), where you really need to optimize for rvalues passed t
|
|||
|
||||
* If the function is going to unconditionally move from the argument, take it by `&&`. See [F.18](#Rf-consume).
|
||||
* If the function is going to keep a copy of the argument, in addition to passing by `const&` (for lvalues),
|
||||
add an overload that passes the parameter by `&&` (for rvalues) and in the body `std::move`s it to its destination. Essentially this overloads a "consume"; see [F.18](#Rf-consume).
|
||||
add an overload that passes the parameter by `&&` (for rvalues) and in the body `std::move`s it to its destination. Essentially this overloads a "consume"; see [F.18](#Rf-consume).
|
||||
* In special cases, such as multiple "input + copy" parameters, consider using perfect forwarding. See [F.19](#Rf-forward).
|
||||
|
||||
##### Example
|
||||
|
@ -2341,7 +2334,7 @@ add an overload that passes the parameter by `&&` (for rvalues) and in the body
|
|||
Avoid "esoteric techniques" such as:
|
||||
|
||||
* Passing arguments as `T&&` "for efficiency".
|
||||
Most rumors about performance advantages from passing by `&&` are false or brittle (but see [F.25](#Rf-pass-ref-move).)
|
||||
Most rumors about performance advantages from passing by `&&` are false or brittle (but see [F.25](#Rf-pass-ref-move).)
|
||||
* Returning `const T&` from assignments and similar operations (see [F.47](#Rf-assignment-op).)
|
||||
|
||||
##### Example
|
||||
|
@ -2368,12 +2361,12 @@ There is no (legitimate) "null reference."
|
|||
If you need the notion of an optional value, use a pointer, `std::optional`, or a special value used to denote "no value."
|
||||
|
||||
##### Enforcement
|
||||
|
||||
* (Simple) ((Foundation)) Warn when a parameter being passed by value has a size greater than `4 * sizeof(int)`.
|
||||
Suggest using a reference to `const` instead.
|
||||
* (Simple) ((Foundation)) Warn when a `const` parameter being passed by reference has a size less than `3 * sizeof(int)`. Suggest passing by value instead.
|
||||
* (Simple) ((Foundation)) Warn when a `const` parameter being passed by reference is `move`d.
|
||||
|
||||
|
||||
### <a name="Rf-inout"></a>F.17: For "in-out" parameters, pass by reference to non-`const`
|
||||
|
||||
##### Reason
|
||||
|
@ -2405,10 +2398,10 @@ Here, the writer of `g()` is supplying a buffer for `f()` to fill, but `f()` sim
|
|||
If the writer of `g()` makes an assumption about the size of `buffer` a bad logic error can happen.
|
||||
|
||||
##### Enforcement
|
||||
|
||||
* (Moderate) ((Foundation)) Warn about functions with reference to non-`const` parameters that do *not* write to them.
|
||||
* (Simple) ((Foundation)) Warn when a non-`const` parameter being passed by reference is `move`d.
|
||||
|
||||
|
||||
### <a name="Rf-consume"></a>F.18: For "consume" parameters, pass by `X&&` and `std::move` the parameter
|
||||
|
||||
##### Reason
|
||||
|
@ -2434,11 +2427,11 @@ For example:
|
|||
} // p gets destroyed
|
||||
|
||||
##### Enforcement
|
||||
|
||||
* Flag all `X&&` parameters (where `X` is not a template type parameter name) where the function body uses them without `std::move`.
|
||||
* Flag access to moved-from objects.
|
||||
* Don't conditionally move from objects
|
||||
|
||||
|
||||
### <a name="Rf-forward"></a>F.19: For "forward" parameters, pass by `TP&&` and only `std::forward` the parameter
|
||||
|
||||
##### Reason
|
||||
|
@ -2457,8 +2450,8 @@ In that case, and only that case, make the parameter `TP&&` where `TP` is a temp
|
|||
??? calls ???
|
||||
|
||||
##### Enforcement
|
||||
* Flag a function that takes a `TP&&` parameter (where `TP` is a template type parameter name) and does anything with it other than `std::forward`ing it exactly once on every static path.
|
||||
|
||||
* Flag a function that takes a `TP&&` parameter (where `TP` is a template type parameter name) and does anything with it other than `std::forward`ing it exactly once on every static path.
|
||||
|
||||
### <a name="Rf-out"></a>F.20: For "out" output values, prefer return values to output parameters
|
||||
|
||||
|
@ -2504,10 +2497,10 @@ It is not recommended to return a `const` value. Such older advice is now obsole
|
|||
void val(int&); // Bad: Is val reading its argument
|
||||
|
||||
##### Enforcement
|
||||
|
||||
* Flag reference to non-`const` parameters that are not read before being written to and are a type that could be cheaply returned; they should be "out" return values.
|
||||
* Flag returning a `const` value. To fix: Remove `const` to return a non-`const` value instead.
|
||||
|
||||
|
||||
### <a name="Rf-out-multi"></a>F.21: To return multiple "out" values, prefer returning a tuple or struct
|
||||
|
||||
##### Reason
|
||||
|
@ -2565,7 +2558,6 @@ In some cases it may be useful to return a specific, user-defined `Value_or_erro
|
|||
* Output parameters should be replaced by return values.
|
||||
An output parameter is one that the function writes to, invokes a non-`const` member function, or passes on as a non-`const`.
|
||||
|
||||
|
||||
### <a name="Rf-ptr"></a>F.22: Use `T*` or `owner<T*>` to designate a single object
|
||||
|
||||
##### Reason
|
||||
|
@ -2653,9 +2645,9 @@ Informal/non-explicit ranges are a source of errors.
|
|||
##### Note
|
||||
|
||||
Ranges are extremely common in C++ code. Typically, they are implicit and their correct use is very hard to ensure.
|
||||
In particular, given a pair of arguments `(p, n)` designating an array [`p`:`p+n`),
|
||||
In particular, given a pair of arguments `(p, n)` designating an array \[`p`:`p+n`),
|
||||
it is in general impossible to know if there really are `n` elements to access following `*p`.
|
||||
`span<T>` and `span_p<T>` are simple helper classes designating a [`p`:`q`) range and a range starting with `p` and ending with the first element for which a predicate is true, respectively.
|
||||
`span<T>` and `span_p<T>` are simple helper classes designating a \[`p`:`q`) range and a range starting with `p` and ending with the first element for which a predicate is true, respectively.
|
||||
|
||||
##### Example
|
||||
|
||||
|
@ -2706,7 +2698,6 @@ When I call `length(s)` should I test for `s == nullptr` first? Should the imple
|
|||
|
||||
**See also**: [Support library](#S-gsl).
|
||||
|
||||
|
||||
### <a name="Rf-unique_ptr"></a>F.26: Use a `unique_ptr<T>` to transfer ownership where a pointer is needed
|
||||
|
||||
##### Reason
|
||||
|
@ -2768,7 +2759,6 @@ Have a single object own the shared object (e.g. a scoped object) and destroy th
|
|||
|
||||
(Not enforceable) This is a too complex pattern to reliably detect.
|
||||
|
||||
|
||||
### <a name="Rf-ptr-ref"></a>F.60: Prefer `T*` over `T&` when "no argument" is a valid option
|
||||
|
||||
##### Reason
|
||||
|
@ -3110,7 +3100,6 @@ Functions can't capture local variables or be declared at local scope; if you ne
|
|||
|
||||
* Warn on use of a named non-generic lambda (e.g., `auto x = [](int i){ /*...*/; };`) that captures nothing and appears at global scope. Write an ordinary function instead.
|
||||
|
||||
|
||||
### <a name="Rf-default-args"></a>F.51: Where there is a choice, prefer default arguments over overloading
|
||||
|
||||
##### Reason
|
||||
|
@ -3145,7 +3134,6 @@ There is not a choice when a set of functions are used to do a semantically equi
|
|||
|
||||
???
|
||||
|
||||
|
||||
### <a name="Rf-reference-capture"></a>F.52: Prefer capturing by reference in lambdas that will be used locally, including passed to algorithms
|
||||
|
||||
##### Reason
|
||||
|
@ -3238,7 +3226,6 @@ This is under active discussion in standardization, and may be addressed in a fu
|
|||
|
||||
* Flag any lambda capture-list that specifies a default capture and also captures `this` (whether explicitly or via default capture)
|
||||
|
||||
|
||||
# <a name="S-class"></a>C: Classes and Class Hierarchies
|
||||
|
||||
A class is a user-defined type, for which a programmer can define the representation, operations, and interfaces.
|
||||
|
@ -3426,7 +3413,6 @@ This is especially important for [overloaded operators](#Ro-namespace).
|
|||
|
||||
* Flag global functions taking argument types from a single namespace.
|
||||
|
||||
|
||||
### <a name="Rc-standalone"></a>C.7: Don't define a class or enum and declare a variable of its type in the same statement
|
||||
|
||||
##### Reason
|
||||
|
@ -3446,7 +3432,6 @@ Mixing a type definition and the definition of another entity in the same declar
|
|||
|
||||
* Flag if the `}` of a class or enumeration definition is not followed by a `;`. The `;` is missing.
|
||||
|
||||
|
||||
### <a name="Rc-class"></a>C.8: use `class` rather that `struct` if any member is non-public
|
||||
|
||||
##### Reason
|
||||
|
@ -3473,7 +3458,6 @@ The data is split in different parts of the class declaration.
|
|||
Different parts of the data has difference access.
|
||||
All of this decreases readability and complicates maintenance.
|
||||
|
||||
|
||||
##### Note
|
||||
|
||||
Prefer to place the interface first in a class [see](#Rl-order).
|
||||
|
@ -3482,7 +3466,6 @@ Prefer to place the interface first in a class [see](#Rl-order).
|
|||
|
||||
Flag classes declared with `struct` if there is a `private` or `public` member.
|
||||
|
||||
|
||||
### <a name="Rc-private"></a>C.9: minimize exposure of members
|
||||
|
||||
##### Reason
|
||||
|
@ -4116,7 +4099,6 @@ We can imagine one case where you could want a protected virtual destructor: Whe
|
|||
|
||||
* A class with any virtual functions should have a destructor that is either public and virtual or else protected and nonvirtual.
|
||||
|
||||
|
||||
### <a name="Rc-dtor-fail"></a>C.36: A destructor may not fail
|
||||
|
||||
##### Reason
|
||||
|
@ -4444,7 +4426,6 @@ Assuming that you want initialization, an explicit default initialization can he
|
|||
int i {}; // default initialize (to 0)
|
||||
};
|
||||
|
||||
|
||||
##### Enforcement
|
||||
|
||||
* Flag classes without a default constructor
|
||||
|
@ -5468,12 +5449,12 @@ The alternative is to make two failure states compare equal and any valid state
|
|||
|
||||
#### Note
|
||||
|
||||
This rule applies to all the usual comparison operators: `!=', `<, `<=`, `>`, and `>=`.
|
||||
This rule applies to all the usual comparison operators: `!=`, `<`, `<=`, `>`, and `>=`.
|
||||
|
||||
##### Enforcement
|
||||
|
||||
* Flag an `operator==()` for which the argument types differ; same for other comparison operators: `!=', `<, `<=`, `>`, and `>=`.
|
||||
* Flag member `operator==()`s; same for other comparison operators: `!=', `<, `<=`, `>`, and `>=`.
|
||||
* Flag an `operator==()` for which the argument types differ; same for other comparison operators: `!=`, `<`, `<=`, `>`, and `>=`.
|
||||
* Flag member `operator==()`s; same for other comparison operators: `!=`, `<`, `<=`, `>`, and `>=`.
|
||||
|
||||
### <a name="Rc-eq-base"></a>C.87: Beware of `==` on base classes
|
||||
|
||||
|
@ -5517,11 +5498,11 @@ Of course there are ways of making `==` work in a hierarchy, but the naive appro
|
|||
|
||||
#### Note
|
||||
|
||||
This rule applies to all the usual comparison operators: `!=', `<, `<=`, `>`, and `>=`.
|
||||
This rule applies to all the usual comparison operators: `!=`, `<`, `<=`, `>`, and `>=`.
|
||||
|
||||
##### Enforcement
|
||||
|
||||
* Flag a virtual `operator==()`; same for other comparison operators: `!=', `<, `<=`, `>`, and `>=`.
|
||||
* Flag a virtual `operator==()`; same for other comparison operators: `!=`, `<`, `<=`, `>`, and `>=`.
|
||||
|
||||
|
||||
|
||||
|
@ -5717,6 +5698,7 @@ Interfaces should normally be composed entirely of public pure virtual functions
|
|||
The `Derived` is `delete`d through its `Goof` interface, so its `string` is leaked.
|
||||
Give `Goof` a virtual destructor and all is well.
|
||||
|
||||
|
||||
##### Enforcement
|
||||
|
||||
* Warn on any class that contains data members and also has an overridable (non-`final`) virtual function.
|
||||
|
@ -5843,7 +5825,6 @@ Use `virtual` only when declaring a new virtual function. Use `override` only wh
|
|||
* Flag overrides with neither `override` nor `final`.
|
||||
* Flag function declarations that use more than one of `virtual`, `override`, and `final`.
|
||||
|
||||
|
||||
### <a name="Rh-kind"></a>C.129: When designing a class hierarchy, distinguish between implementation inheritance and interface inheritance
|
||||
|
||||
##### Reason
|
||||
|
@ -5888,7 +5869,6 @@ Note that because of language rules, the covariant return type cannot be a smart
|
|||
* Flag a class with a virtual function and a non-user-defined copy operation.
|
||||
* Flag an assignment of base class objects (objects of a class from which another has been derived).
|
||||
|
||||
|
||||
### <a name="Rh-get"></a>C.131: Avoid trivial getters and setters
|
||||
|
||||
##### Reason
|
||||
|
@ -5995,7 +5975,7 @@ Data members in category B should be `private` or `const`. This is because encap
|
|||
Most classes are either all A or all B:
|
||||
|
||||
* *All public*: If you're writing an aggregate bundle-of-variables without an invariant across those variables, then all the variables should be `public`.
|
||||
[By convention, declare such classes `struct` rather than `class`](#Rc-struct)
|
||||
[By convention, declare such classes `struct` rather than `class`](#Rc-struct)
|
||||
* *All private*: If you’re writing a type that maintains an invariant, then all the non-`const` variables should be private -- it should be encapsulated.
|
||||
|
||||
##### Exceptions
|
||||
|
@ -6006,7 +5986,6 @@ Occasionally classes will mix A and B, usually for debug reasons. An encapsulate
|
|||
|
||||
Flag any class that has non-`const` data members with different access levels.
|
||||
|
||||
|
||||
### <a name="Rh-mi-interface"></a>C.135: Use multiple inheritance to represent multiple distinct interfaces
|
||||
|
||||
##### Reason
|
||||
|
@ -6076,7 +6055,6 @@ This a relatively rare use because implementation can often be organized into a
|
|||
|
||||
???
|
||||
|
||||
|
||||
### <a name="Rh-final"></a>C.139: Use `final` sparingly
|
||||
|
||||
##### Reason
|
||||
|
@ -6138,6 +6116,7 @@ However, misuses are (or at least has been) far more common.
|
|||
|
||||
Flag uses of `final`.
|
||||
|
||||
|
||||
## <a name="Rh-virtual-default-arg"></a>C.140: Do not provide different default arguments for a virtual function and an overrider
|
||||
|
||||
##### Reason
|
||||
|
@ -6587,8 +6566,6 @@ The string allocated for `s` and assigned to `p` is destroyed before it can be u
|
|||
|
||||
Flag all conversion operators.
|
||||
|
||||
|
||||
|
||||
### <a name="Ro-custom"></a>C.165: Use `using` for customization points
|
||||
|
||||
##### Reason
|
||||
|
@ -6663,7 +6640,7 @@ Many parts of the C++ semantics assumes its default meaning.
|
|||
|
||||
If you "mess with" operator `&` be sure that its definition has matching meanings for `->`, `[]`, `*`, and `.` on the result type.
|
||||
Note that operator `.` currently cannot be overloaded so a perfect system is impossible.
|
||||
We hope to remedy that: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4477.pdf.
|
||||
We hope to remedy that: <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4477.pdf>.
|
||||
Note that `std::addressof()` always yields a built-in pointer.
|
||||
|
||||
##### Enforcement
|
||||
|
@ -8180,10 +8157,10 @@ Do not declare a non-type with the same name as a type in the same scope. This r
|
|||
Antique header files might declare non-types and types with the same name in the same scope.
|
||||
|
||||
##### Enforcement
|
||||
|
||||
* Check names against a list of known confusing letter and digit combinations.
|
||||
* Flag a declaration of a variable, function, or enumerator that hides a class or enumeration declared in the same scope.
|
||||
|
||||
|
||||
### <a name="Res-not-CAPS"></a>ES.9: Avoid `ALL_CAPS` names
|
||||
|
||||
##### Reason
|
||||
|
@ -9193,7 +9170,6 @@ Readability.
|
|||
|
||||
Flag empty statements that are not blocks and don't contain comments.
|
||||
|
||||
|
||||
### <a name="Res-loop-counter"></a>ES.86: Avoid modifying loop control variables inside the body of raw for-loops
|
||||
|
||||
##### Reason
|
||||
|
@ -9224,8 +9200,6 @@ The loop control up front should enable correct reasoning about what is happenin
|
|||
|
||||
Flag variables that are potentially updated (have a non-const use) in both the loop control iteration-expression and the loop body.
|
||||
|
||||
|
||||
|
||||
## ES.expr: Expressions
|
||||
|
||||
Expressions manipulate values.
|
||||
|
@ -9586,7 +9560,6 @@ Constructs that cannot overflow do not overflow (and usually run faster):
|
|||
|
||||
Look for explicit range checks and heuristically suggest alternatives.
|
||||
|
||||
|
||||
### <a name="Res-move"></a>ES.56: Write `std::move()` only when you need to explicitly move an object to another scope
|
||||
|
||||
##### Reason
|
||||
|
@ -9644,7 +9617,7 @@ And after you do that, assume the object has been moved from (see [C.64](#Rc-mov
|
|||
##### Notes
|
||||
|
||||
`std::move()` is a cast to `&&` in disguise; it doesn't itself move anything, but marks a named object as a candidate that can be moved from.
|
||||
The language already knows the common cases where objects can be moved from, especially when returning values from functions, so don't complicate code with redundant `std::move()'s.
|
||||
The language already knows the common cases where objects can be moved from, especially when returning values from functions, so don't complicate code with redundant `std::move()`'s.
|
||||
|
||||
Never write `std::move()` just because you've heard "it's more efficient."
|
||||
In general, don't believe claims of "efficiency" without data (???).
|
||||
|
@ -9661,6 +9634,7 @@ In general, don't complicate your code without reason (??)
|
|||
Never write `return move(local_variable);`, because the language already knows the variable is a move candidate.
|
||||
Writing `move` in this code won't help, and can actually be detrimental because on some compilers it interferes with RVO (the return value optimization) by creating an additional reference alias to the local variable.
|
||||
|
||||
|
||||
##### Example, bad
|
||||
|
||||
vector<int> v = std::move(make_vector()); // bad; the std::move is entirely redundant
|
||||
|
@ -9694,7 +9668,6 @@ The language already knows that a returned value is a temporary object that can
|
|||
* Flag when `std::forward` is applied to other than a forwarding reference. (More general case of the previous rule to cover the non-moving cases.)
|
||||
* Flag when an object is potentially moved from and the next operation is a `const` operation; there should first be an intervening non-`const` operation, ideally assignment, to first reset the object's value.
|
||||
|
||||
|
||||
### <a name="Res-new"></a>ES.60: Avoid `new` and `delete` outside resource management functions
|
||||
|
||||
##### Reason
|
||||
|
@ -9722,7 +9695,6 @@ There can be code in the `...` part that causes the `delete` never to happen.
|
|||
|
||||
Flag naked `new`s and naked `delete`s.
|
||||
|
||||
|
||||
### <a name="Res-del"></a>ES.61: delete arrays using `delete[]` and non-arrays using `delete`
|
||||
|
||||
##### Reason
|
||||
|
@ -9958,7 +9930,6 @@ This also applies to `%`.
|
|||
|
||||
* Flag division by an integral value that could be zero
|
||||
|
||||
|
||||
# <a name="S-performance"></a>PER: Performance
|
||||
|
||||
??? should this section be in the main guide???
|
||||
|
@ -10024,7 +9995,6 @@ only as impactful as a 5% improvement on B. (If you don't even know how much
|
|||
time is spent on A or B, see <a href="#Rper-reason">PER.1</a> and <a
|
||||
href="#Rper-Knuth">PER.2</a>.)
|
||||
|
||||
|
||||
### <a name="Rper-simple"></a>PER.4: Don't assume that complicated code is necessarily faster than simple code
|
||||
|
||||
##### Reason
|
||||
|
@ -10176,6 +10146,7 @@ in a thread-friendly way.
|
|||
|
||||
The concurrency/parallelism rules in this document are designed with three goals
|
||||
in mind:
|
||||
|
||||
* To help you write code that is amenable to being used in a threaded
|
||||
environment
|
||||
* To show clean, safe ways to use the threading primitives offered by the
|
||||
|
@ -10227,6 +10198,7 @@ Note that this applies most urgently to library code and least urgently to stand
|
|||
Although `cached_computation` works perfectly in a single-threaded environment, in a multi-threaded environment the two `static` variables result in data races and thus undefined behavior.
|
||||
|
||||
There are several ways that this example could be made safe for a multi-threaded environment:
|
||||
|
||||
* Delegate concurrency concerns upwards to the caller.
|
||||
* Mark the `static` variables as `thread_local` (which might make caching less effective).
|
||||
* Implement concurrency control, for example, protecting the two `static` variables with a `static` lock (which might reduce performance).
|
||||
|
@ -10979,7 +10951,6 @@ The problem is of course that the caller now have to remember to test the return
|
|||
|
||||
Possible (only) for specific versions of this idea: e.g., test for systematic test of `valid()` after resource handle construction
|
||||
|
||||
|
||||
## <a name="Re-no-throw-crash"></a>E.26: If you can't throw exceptions, consider failing fast
|
||||
|
||||
##### Reason
|
||||
|
@ -11160,6 +11131,7 @@ A not uncommon technique is to gather cleanup at the end of the function to avoi
|
|||
goto exit;
|
||||
}
|
||||
// ...
|
||||
|
||||
exit:
|
||||
if (g1.valid()) cleanup(g1);
|
||||
if (g1.valid()) cleanup(g2);
|
||||
|
@ -11198,7 +11170,6 @@ C-stye error handling is based on the global variable `errno`, so it is essentia
|
|||
|
||||
Awkward.
|
||||
|
||||
|
||||
# <a name="S-const"></a>Con: Constants and Immutability
|
||||
|
||||
You can't have a race condition on a constant.
|
||||
|
@ -11270,7 +11241,6 @@ This gives a more precise statement of design intent, better readability, more e
|
|||
|
||||
* Flag a member function that is not marked `const`, but that does not perform a non-`const` operation on any member variable.
|
||||
|
||||
|
||||
### <a name="Rconst-ref"></a>Con.3: By default, pass pointers and references to `const`s
|
||||
|
||||
##### Reason
|
||||
|
@ -12140,11 +12110,10 @@ It could even be less efficient.
|
|||
It can be a nuisance to define all operators, but not hard.
|
||||
Hopefully, C++17 will give you comparison operators by default.
|
||||
|
||||
|
||||
##### Enforcement
|
||||
|
||||
* Flag classes the support "odd" subsets of a set of operators, e.g., `==` but not `!=` or `+` but not `-`.
|
||||
Yes, `std::string` is "odd", but it's too late to change that.
|
||||
Yes, `std::string` is "odd", but it's too late to change that.
|
||||
|
||||
### <a name="Rt-alias"></a>T.42: Use template aliases to simplify notation and hide implementation details
|
||||
|
||||
|
@ -12557,7 +12526,6 @@ When `concept`s become available such alternatives can be distinguished directly
|
|||
|
||||
???
|
||||
|
||||
|
||||
### <a name="Rt-customization"></a>T.69: Inside a template, don't make an unqualified nonmember function call unless you intend it to be a customization point
|
||||
|
||||
##### Reason
|
||||
|
@ -13526,7 +13494,6 @@ Don't replicate the work of others.
|
|||
Benefit from other people's work when they make improvements.
|
||||
Help other people when you make improvements.
|
||||
|
||||
|
||||
### <a name="Rsl-sl"></a>SL.2: Prefer the standard library to other libraries
|
||||
|
||||
##### Reason
|
||||
|
@ -13534,12 +13501,11 @@ Help other people when you make improvements.
|
|||
More people know the standard library.
|
||||
It is more likely to be stable, well-maintained, and widely available than your own code or most other libraries.
|
||||
|
||||
|
||||
## SL.con: Containers
|
||||
|
||||
* [SL.10: Prefer using STL `array` or `vector` instead of a C array](#Rsl-arrays)
|
||||
* [SL.11: Prefer using STL `vector` by default unless you have a reason to use a different container](#Rsl-vector)
|
||||
???
|
||||
???
|
||||
|
||||
### <a name="Rsl-arrays"></a>SL.10: Prefer using STL `array` or `vector` instead of a C array
|
||||
|
||||
|
@ -13566,7 +13532,6 @@ For a variable-length array, use `std::vector`, which additionally can change it
|
|||
|
||||
* Flag declaration of a C array inside a function or class that also declares an STL container (to avoid excessive noisy warnings on legacy non-STL code). To fix: At least change the C array to a `std::array`.
|
||||
|
||||
|
||||
### <a name="Rsl-vector"></a>SL.11: Prefer using STL `vector` by default unless you have a reason to use a different container
|
||||
|
||||
##### Reason
|
||||
|
@ -13591,7 +13556,6 @@ If you have a good reason to use another container, use that instead. For exampl
|
|||
|
||||
* Flag a `vector` whose size never changes after construction (such as because it's `const` or because no non-`const` functions are called on it). To fix: Use an `array` instead.
|
||||
|
||||
|
||||
## SL.str: String
|
||||
|
||||
???
|
||||
|
@ -14379,8 +14343,8 @@ If something is not supposed to be `nullptr`, say so:
|
|||
* `not_null<T>` // `T` is usually a pointer type (e.g., `not_null<int*>` and `not_null<owner<Foo*>>`) that may not be `nullptr`.
|
||||
`T` can be any type for which `==nullptr` is meaningful.
|
||||
|
||||
* `span<T>` // [`p`:`p+n`), constructor from `{p, q}` and `{p, n}`; `T` is the pointer type
|
||||
* `span_p<T>` // `{p, predicate}` [`p`:`q`) where `q` is the first element for which `predicate(*p)` is true
|
||||
* `span<T>` // \[`p`:`p+n`), constructor from `{p, q}` and `{p, n}`; `T` is the pointer type
|
||||
* `span_p<T>` // `{p, predicate}` \[`p`:`q`) where `q` is the first element for which `predicate(*p)` is true
|
||||
* `string_span` // `span<char>`
|
||||
* `cstring_span` // `span<const char>`
|
||||
|
||||
|
@ -14456,7 +14420,6 @@ The notation is that of the ISO WG21 Concepts TS (???ref???).
|
|||
|
||||
Described in [Lifetimes paper](https://github.com/isocpp/CppCoreGuidelines/blob/master/docs/Lifetimes%20I%20and%20II%20-%20v0.9.1.pdf).
|
||||
|
||||
|
||||
# <a name="S-naming"></a>NL: Naming and layout rules
|
||||
|
||||
Consistent naming and layout are helpful. If for no other reason because it minimizes "my style is better than your style" arguments.
|
||||
|
@ -14912,8 +14875,8 @@ These coding standards are written using [CommonMark](http://commonmark.org), an
|
|||
|
||||
We are considering the following extensions from [GitHub Flavored Markdown (GFM)](https://help.github.com/articles/github-flavored-markdown/):
|
||||
|
||||
- fenced code blocks (consistently using indented vs. fenced is under discussion)
|
||||
- tables (none yet but we'll likely need them, and this is a GFM extension)
|
||||
* fenced code blocks (consistently using indented vs. fenced is under discussion)
|
||||
* tables (none yet but we'll likely need them, and this is a GFM extension)
|
||||
|
||||
Avoid other HTML tags and other extensions.
|
||||
|
||||
|
@ -15039,7 +15002,7 @@ In this example, `email` will be constructed before `first` and `last` because i
|
|||
|
||||
If the class definition and the constructor body are in separate files, the long-distance influence that the order of member variable declarations has over the constructor's correctness will be even harder to spot.
|
||||
|
||||
**References**
|
||||
**References**:
|
||||
|
||||
[[Cline99]](#Cline99) §22.03-11, [[Dewhurst03]](Dewhurst03) §52-53, [[Koenig97]](#Koenig97) §4, [[Lakos96]](#Lakos96) §10.3.5, [[Meyers97]](#Meyers97) §13, [[Murray93]](#Murray93) §2.1.3, [[Sutter00]](#Sutter00) §47
|
||||
|
||||
|
@ -15518,7 +15481,6 @@ See the Exceptions in [F.20](#Rf-out).
|
|||
|
||||
Check for pointers and references returned from functions and see if they are assigned to resource handles (e.g., to a `unique_ptr`).
|
||||
|
||||
|
||||
### <a name="Cr-handle"></a>If a class is a resource handle, it needs a constructor, a destructor, and copy and/or move operations
|
||||
|
||||
##### Reason
|
||||
|
@ -15579,7 +15541,7 @@ A relatively informal definition of terms used in the guidelines
|
|||
* *approximation*: something (e.g., a value or a design) that is close to the perfect or ideal (value or design).
|
||||
Often an approximation is a result of trade-offs among ideals.
|
||||
* *argument*: a value passed to a function or a template, in which it is accessed through a parameter.
|
||||
* *array*: a homogeneous sequence of elements, usually numbered, e.g., [0:max).
|
||||
* *array*: a homogeneous sequence of elements, usually numbered, e.g., \[0:max).
|
||||
* *assertion*: a statement inserted into a program to state (assert) that something must always be true at this point in the program.
|
||||
* *base class*: a class used as the base of a class hierarchy. Typically a base class has one or more virtual functions.
|
||||
* *bit*: the basic unit of information in a computer. A bit can have the value 0 or the value 1.
|
||||
|
@ -15608,7 +15570,7 @@ A relatively informal definition of terms used in the guidelines
|
|||
* *debugging*: the act of searching for and removing errors from a program; usually far less systematic than testing.
|
||||
* *declaration*: the specification of a name with its type in a program.
|
||||
* *definition*: a declaration of an entity that supplies all information necessary to complete a program using the entity.
|
||||
Simplified definition: a declaration that allocates memory.
|
||||
Simplified definition: a declaration that allocates memory.
|
||||
* *derived class*: a class derived from one or more base classes.
|
||||
* *design*: an overall description of how a piece of software should operate to meet its specification.
|
||||
* *destructor*: an operation that is implicitly invoked (called) when an object is destroyed (e.g., at the end of a scope). Often, it releases resources.
|
||||
|
@ -15667,7 +15629,7 @@ Simplified definition: a declaration that allocates memory.
|
|||
* *pseudo code*: a description of a computation written in an informal notation rather than a programming language.
|
||||
* *pure virtual function*: a virtual function that must be overridden in a derived class.
|
||||
* *RAII*: (“Resource Acquisition Is Initialization”) a basic technique for resource management based on scopes.
|
||||
* *range*: a sequence of values that can be described by a start point and an end point. For example, [0:5) means the values 0, 1, 2, 3, and 4.
|
||||
* *range*: a sequence of values that can be described by a start point and an end point. For example, \[0:5) means the values 0, 1, 2, 3, and 4.
|
||||
* *regular expression*: a notation for patterns in character strings.
|
||||
* *recursion*: the act of a function calling itself; see also iteration.
|
||||
* *reference*: (1) a value describing the location of a typed value in memory; (2) a variable holding such a value.
|
||||
|
@ -15702,9 +15664,6 @@ Simplified definition: a declaration that allocates memory.
|
|||
* *virtual function*: a member function that can be overridden in a derived class.
|
||||
* *word*: a basic unit of memory in a computer, often the unit used to hold an integer.
|
||||
|
||||
|
||||
|
||||
|
||||
# <a name="S-unclassified"></a>To-do: Unclassified proto-rules
|
||||
|
||||
This is our to-do list.
|
||||
|
@ -15719,7 +15678,7 @@ Alternatively, we will decide that no change is needed and delete the entry.
|
|||
* Avoid implicit conversions
|
||||
* Const member functions should be thread safe "¦ aka, but I don't really change the variable, just assign it a value the first time it’s called "¦ argh
|
||||
* Always initialize variables, use initialization lists for member variables.
|
||||
* Anyone writing a public interface which takes or returns void* should have their toes set on fire. That one has been a personal favorite of mine for a number of years. :)
|
||||
* Anyone writing a public interface which takes or returns `void*` should have their toes set on fire. That one has been a personal favorite of mine for a number of years. :)
|
||||
* Use `const`-ness wherever possible: member functions, variables and (yippee) `const_iterators`
|
||||
* Use `auto`
|
||||
* `(size)` vs. `{initializers}` vs. `{Extent{size}}`
|
||||
|
@ -15758,7 +15717,7 @@ Alternatively, we will decide that no change is needed and delete the entry.
|
|||
* When using a `condition_variable`, always protect the condition by a mutex (atomic bool whose value is set outside of the mutex is wrong!), and use the same mutex for the condition variable itself.
|
||||
* Never use `atomic_compare_exchange_strong` with `std::atomic<user-defined-struct>` (differences in padding matter, while `compare_exchange_weak` in a loop converges to stable padding)
|
||||
* individual `shared_future` objects are not thread-safe: two threads cannot wait on the same `shared_future` object (they can wait on copies of a `shared_future` that refer to the same shared state)
|
||||
* individual `shared_ptr` objects are not thread-safe: different threads can call non-`const` member functions on _different_ `shared_ptr`s that refer to the same shared object, but one thread cannot call a non-`const` member function of a `shared_ptr` object while another thread accesses that same `shared_ptr` object (if you need that, consider `atomic_shared_ptr` instead)
|
||||
* individual `shared_ptr` objects are not thread-safe: different threads can call non-`const` member functions on *different* `shared_ptr`s that refer to the same shared object, but one thread cannot call a non-`const` member function of a `shared_ptr` object while another thread accesses that same `shared_ptr` object (if you need that, consider `atomic_shared_ptr` instead)
|
||||
|
||||
* rules for arithmetic
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user