mirror of
https://github.com/isocpp/CppCoreGuidelines.git
synced 2024-03-22 13:30:58 +08:00
Editorial changes for PER, CP, E, and T.
This commit is contained in:
parent
7ae6ad4eb7
commit
20ed3d12fd
|
@ -9616,7 +9616,7 @@ See also:
|
|||
|
||||
It is hard to be certain that concurrency isn't used now or sometime in the future.
|
||||
Code gets re-used.
|
||||
Libraries using threads my be used from some other part of the program.
|
||||
Libraries using threads may be used from some other part of the program.
|
||||
Note that this applies most urgently to library code and least urgently to stand-alone applications.
|
||||
|
||||
##### Example
|
||||
|
@ -9649,7 +9649,7 @@ There are several ways that this example could be made safe for a multi-threaded
|
|||
However, there are also many examples where code that was "known" to never run in a multi-threaded program
|
||||
was run as part of a multi-threaded program. Often years later.
|
||||
Typically, such programs lead to a painful effort to remove data races.
|
||||
Therefore, code that is never intended to run in a multi-threaded environment should be clearly labeled as such.
|
||||
Therefore, code that is never intended to run in a multi-threaded environment should be clearly labeled as such and ideally come with compile or run-time enforcement mechanisms to catch those usage bugs early.
|
||||
|
||||
### <a name="Rconc-races"></a>CP.2: Avoid data races
|
||||
|
||||
|
@ -9735,7 +9735,7 @@ Error handling involves:
|
|||
* Preserve the state of a program in a valid state
|
||||
* Avoid resource leaks
|
||||
|
||||
It is not possible to recover from all errors. If recovery from an error is not possible, it is important to quickly "get out" in a well-defined way. A strategy for error handling must be simple, or it becomes a source of even worse errors.
|
||||
It is not possible to recover from all errors. If recovery from an error is not possible, it is important to quickly "get out" in a well-defined way. A strategy for error handling must be simple, or it becomes a source of even worse errors. Untested and rarely executed error-handling code is itself the source of many bugs.
|
||||
|
||||
The rules are designed to help avoid several kinds of errors:
|
||||
|
||||
|
@ -9861,7 +9861,7 @@ There is nothing exceptional about finding a value in a `vector`.
|
|||
|
||||
##### Reason
|
||||
|
||||
To use an objects it must be in a valid state (defined formally or informally by an invariant) and to recover from an error every object not destroyed must be in a valid state.
|
||||
To use an object it must be in a valid state (defined formally or informally by an invariant) and to recover from an error every object not destroyed must be in a valid state.
|
||||
|
||||
##### Note
|
||||
|
||||
|
@ -9872,7 +9872,7 @@ An [invariant](#Rc-struct) is logical condition for the members of an object tha
|
|||
##### Reason
|
||||
|
||||
Leaving an object without its invariant established is asking for trouble.
|
||||
Not all member function can be called.
|
||||
Not all member functions can be called.
|
||||
|
||||
##### Example
|
||||
|
||||
|
@ -9917,7 +9917,7 @@ This is verbose. In larger code with multiple possible `throw`s explicit release
|
|||
|
||||
void f3(int i) // OK: resource management done by a handle
|
||||
{
|
||||
auto p = make_unique<int[12]>();
|
||||
auto p = make_unique<int[]>(12);
|
||||
// ...
|
||||
if (i < 17) throw Bad {"in f()", i};
|
||||
// ...
|
||||
|
@ -9927,7 +9927,7 @@ Note that this works even when the `throw` is implicit because it happened in a
|
|||
|
||||
void f4(int i) // OK: resource management done by a handle
|
||||
{
|
||||
auto p = make_unique<int[12]>();
|
||||
auto p = make_unique<int[]>(12);
|
||||
// ...
|
||||
helper(i); // may throw
|
||||
// ...
|
||||
|
@ -9954,12 +9954,12 @@ First challenge that assumption; there are many anti-exceptions myths around.
|
|||
We know of only a few good reasons:
|
||||
|
||||
* We are on a system so small that the exception support would eat up most of our 2K or memory.
|
||||
* We are in a hard-real-time system and we don't have tools that allows us that an exception is handled within the required time.
|
||||
* We are in a hard-real-time system and we don't have tools that guarantee us that an exception is handled within the required time.
|
||||
* We are in a system with tons of legacy code using lots of pointers in difficult-to-understand ways
|
||||
(in particular without a recognizable ownership strategy) so that exceptions could cause leaks.
|
||||
* We get fired if we challenge our manager's ancient wisdom.
|
||||
|
||||
Only the first of these reasons is fundamental, so whenever possible, use exception to implement RAII.
|
||||
Only the first of these reasons is fundamental, so whenever possible, use exceptions to implement RAII, or design your RAII objects to never fail.
|
||||
When exceptions cannot be used, simulate RAII.
|
||||
That is, systematically check that objects are valid after construction and still release all resources in the destructor.
|
||||
One strategy is to add a `valid()` operation to every resource handle:
|
||||
|
@ -10031,7 +10031,7 @@ Many standard library functions are `noexcept` including all the standard librar
|
|||
// ... do something ...
|
||||
}
|
||||
|
||||
The `noexcept` here states that I am not willing or able to handle the situation where I cannot construct the local `vector`. That is, I consider memory exhaustion a serious design error (on line with hardware failures) so that I'm willing to crash the program if it happens.
|
||||
The `noexcept` here states that I am not willing or able to handle the situation where I cannot construct the local `vector`. That is, I consider memory exhaustion a serious design error (on par with hardware failures) so that I'm willing to crash the program if it happens.
|
||||
|
||||
**See also**: [discussion](#Sd-noexcept).
|
||||
|
||||
|
@ -10164,7 +10164,7 @@ Instead, use:
|
|||
|
||||
##### Enforcement
|
||||
|
||||
Flag by-value exceptions if their type are part of a hierarchy (could require whole-program analysis to be perfect).
|
||||
Flag by-value exceptions if their types are part of a hierarchy (could require whole-program analysis to be perfect).
|
||||
|
||||
### <a name="Re-never-fail"></a>E.16: Destructors, deallocation, and `swap` must never fail
|
||||
|
||||
|
@ -10186,7 +10186,7 @@ We don't know how to write reliable programs if a destructor, a swap, or a memor
|
|||
|
||||
##### Note
|
||||
|
||||
Many have tried to write reliable code violating this rule for examples such as a network connection that "refuses to close". To the best of our knowledge nobody has found a general way of doing this though occasionally, for very specific examples, you can get away with setting some state for future cleanup. Every example, we have seen of this is error-prone, specialized, and usually buggy.
|
||||
Many have tried to write reliable code violating this rule for examples such as a network connection that "refuses to close". To the best of our knowledge nobody has found a general way of doing this though occasionally, for very specific examples, you can get away with setting some state for future cleanup. Every example we have seen of this is error-prone, specialized, and usually buggy.
|
||||
|
||||
##### Note
|
||||
|
||||
|
@ -10194,7 +10194,7 @@ The standard library assumes that destructors, deallocation functions (e.g., `op
|
|||
|
||||
##### Note
|
||||
|
||||
Deallocation functions, including `operator delete`, must be `noexcept`. `swap` functions must be `noexcept`. Most destructors are implicitly `noexcept` by default. destructors, make them `noexcept`.
|
||||
Deallocation functions, including `operator delete`, must be `noexcept`. `swap` functions must be `noexcept`. Most destructors are implicitly `noexcept` by default.
|
||||
|
||||
##### Enforcement
|
||||
|
||||
|
@ -10268,7 +10268,7 @@ Let cleanup actions on the unwinding path be handled by [RAII](#Re-raii).
|
|||
# <a name="S-const"></a>Con: Constants and Immutability
|
||||
|
||||
You can't have a race condition on a constant.
|
||||
it is easier to reason about a program when many of the objects cannot change their values.
|
||||
It is easier to reason about a program when many of the objects cannot change their values.
|
||||
Interfaces that promises "no change" of objects passed as arguments greatly increase readability.
|
||||
|
||||
Constant rule summary:
|
||||
|
@ -10362,6 +10362,10 @@ This gives a more precise statement of design intent, better readability, more e
|
|||
|
||||
???
|
||||
|
||||
##### Note
|
||||
|
||||
See F.4.
|
||||
|
||||
##### Enforcement
|
||||
|
||||
???
|
||||
|
@ -10749,7 +10753,7 @@ It is better and simpler just to use `Sortable`:
|
|||
|
||||
##### Note
|
||||
|
||||
The set of "standard" concepts is evolving as we approaches real (ISO) standardization.
|
||||
The set of "standard" concepts is evolving as we approach real (ISO) standardization.
|
||||
|
||||
##### Note
|
||||
|
||||
|
@ -10900,7 +10904,7 @@ Examples of complete sets are
|
|||
##### Reason
|
||||
|
||||
A meaningful/useful concept has a semantic meaning.
|
||||
Expressing this semantics in a informal, semi-formal, or formal way makes the concept comprehensible to readers and the effort to express it can catch conceptual errors.
|
||||
Expressing these semantics in an informal, semi-formal, or formal way makes the concept comprehensible to readers and the effort to express it can catch conceptual errors.
|
||||
Specifying semantics is a powerful design tool.
|
||||
|
||||
##### Example
|
||||
|
@ -11065,7 +11069,7 @@ Conversions are taken into account. You don't have to remember the names of all
|
|||
##### Reason
|
||||
|
||||
Function objects can carry more information through an interface than a "plain" pointer to function.
|
||||
In general, passing function objects give better performance than passing pointers to functions.
|
||||
In general, passing function objects gives better performance than passing pointers to functions.
|
||||
|
||||
##### Example
|
||||
|
||||
|
@ -11136,7 +11140,7 @@ This saves the user of `Matrix` from having to know that its elements are stored
|
|||
##### Example
|
||||
|
||||
template<typename T>
|
||||
using Value_type<T> = container_traits<T>::value_type;
|
||||
using Value_type = typename container_traits<T>::value_type;
|
||||
|
||||
This saves the user of `Value_type` from having to know the technique used to implement `value_type`s.
|
||||
|
||||
|
@ -11497,7 +11501,7 @@ There are three major ways to let calling code customize a template.
|
|||
|
||||
Templates are the backbone of C++'s support for generic programming and class hierarchies the backbone of its support
|
||||
for object-oriented programming.
|
||||
The two language mechanisms can be use effectively in combination, but a few design pitfalls must be avoided.
|
||||
The two language mechanisms can be used effectively in combination, but a few design pitfalls must be avoided.
|
||||
|
||||
### <a name="Rt-hier"></a>T.80: Do not naively templatize a class hierarchy
|
||||
|
||||
|
@ -11917,7 +11921,8 @@ That makes the code concise and gives better locality than alternatives.
|
|||
|
||||
##### Example
|
||||
|
||||
??? for-loop equivalent
|
||||
auto earlyUsersEnd = std::remove_if(users.begin(), users.end(),
|
||||
[](const User &a) { return a.id > 100; });
|
||||
|
||||
**Exception**: Naming a lambda can be useful for clarity even if it is used only once
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user