Committing PR #1640 to main branch

This commit is contained in:
hsutter 2020-07-03 17:43:13 -07:00
parent ac7079b012
commit 43bbde7fc9

View File

@ -1,6 +1,6 @@
# <a name="main"></a>C++ Core Guidelines
May 28, 2020
July 3, 2020
Editors:
@ -314,7 +314,7 @@ The rules are not value-neutral.
They are meant to make code simpler and more correct/safer than most existing C++ code, without loss of performance.
They are meant to inhibit perfectly valid C++ code that correlates with errors, spurious complexity, and poor performance.
The rules are not precise to the point where a person (or machine) can follow them blindly.
The rules are not precise to the point where a person (or machine) can follow them without thinking.
The enforcement parts try to be that, but we would rather leave a rule or a definition a bit vague
and open to interpretation than specify something precisely and wrong.
Sometimes, precision comes only with time and experience.
@ -352,7 +352,7 @@ We try to resolve those using tools.
Each rule has an **Enforcement** section listing ideas for enforcement.
Enforcement might be done by code review, by static analysis, by compiler, or by run-time checks.
Wherever possible, we prefer "mechanical" checking (humans are slow, inaccurate, and bore easily) and static checking.
Run-time checks are suggested only rarely where no alternative exists; we do not want to introduce "distributed fat".
Run-time checks are suggested only rarely where no alternative exists; we do not want to introduce "distributed bloat".
Where appropriate, we label a rule (in the **Enforcement** sections) with the name of groups of related rules (called "profiles").
A rule can be part of several profiles, or none.
For a start, we have a few profiles corresponding to common needs (desires, ideals):
@ -4724,7 +4724,7 @@ These operations disagree about copy semantics. This will lead to confusion and
## <a name="SS-dtor"></a>C.dtor: Destructors
"Does this class need a destructor?" is a surprisingly powerful design question.
"Does this class need a destructor?" is a surprisingly insightful design question.
For most classes the answer is "no" either because the class holds no resources or because destruction is handled by [the rule of zero](#Rc-zero);
that is, its members can take care of themselves as concerns destruction.
If the answer is "yes", much of the design of the class follows (see [the rule of five](#Rc-five)).
@ -5561,7 +5561,7 @@ Makes it explicit that the same value is expected to be used in all constructors
// ...
};
How would a maintainer know whether `j` was deliberately uninitialized (probably a poor idea anyway) and whether it was intentional to give `s` the default value `""` in one case and `qqq` in another (almost certainly a bug)? The problem with `j` (forgetting to initialize a member) often happens when a new member is added to an existing class.
How would a maintainer know whether `j` was deliberately uninitialized (probably a bad idea anyway) and whether it was intentional to give `s` the default value `""` in one case and `qqq` in another (almost certainly a bug)? The problem with `j` (forgetting to initialize a member) often happens when a new member is added to an existing class.
##### Example
@ -6710,7 +6710,7 @@ In particular, ensure that an object compares equal to its copy.
{
Sorted_vector<string> v2 {v};
if (v != v2)
cout << "insanity rules!\n";
cout << "Behavior against reason and logic.\n";
// ...
}
@ -8720,7 +8720,7 @@ but at least we can see that something tricky is going on.
##### Note
Unfortunately, `union`s are commonly used for type punning.
We don't consider "sometimes, it works as expected" a strong argument.
We don't consider "sometimes, it works as expected" a conclusive argument.
C++17 introduced a distinct type `std::byte` to facilitate operations on raw object representation. Use that type instead of `unsigned char` or `char` for these operations.
@ -10688,7 +10688,7 @@ Readability. Limit the scope in which a variable can be used. Don't risk used-be
##### Example, bad
SomeLargeType var;
SomeLargeType var; // Hard-to-read CaMeLcAsEvArIaBlE
if (cond) // some non-trivial condition
Set(&var);
@ -13433,7 +13433,7 @@ Alternatives for users
This section contains rules for people who need high performance or low-latency.
That is, these are rules that relate to how to use as little time and as few resources as possible to achieve a task in a predictably short time.
The rules in this section are more restrictive and intrusive than what is needed for many (most) applications.
Do not blindly try to follow them in general code: achieving the goals of low latency requires extra work.
Do not naïvely try to follow them in general code: achieving the goals of low latency requires extra work.
Performance rule summary:
@ -14707,7 +14707,7 @@ Thread creation is expensive.
// process
}
void master(istream& is)
void dispatcher(istream& is)
{
for (Message m; is >> m; )
run_list.push_back(new thread(worker, m));
@ -14719,7 +14719,7 @@ Instead, we could have a set of pre-created worker threads processing the messag
Sync_queue<Message> work;
void master(istream& is)
void dispatcher(istream& is)
{
for (Message m; is >> m; )
work.put(m);
@ -18126,7 +18126,7 @@ Templating a class hierarchy that has many functions, especially many virtual fu
Vector<int> vi;
Vector<string> vs;
It is probably a dumb idea to define a `sort` as a member function of a container, but it is not unheard of and it makes a good example of what not to do.
It is probably a bad idea to define a `sort` as a member function of a container, but it is not unheard of and it makes a good example of what not to do.
Given this, the compiler cannot know if `vector<int>::sort()` is called, so it must generate code for it.
Similar for `vector<string>::sort()`.
@ -20107,7 +20107,7 @@ However, in the context of the styles of programming we recommend and support wi
Even today, there can be contexts where the rules make sense.
For example, lack of suitable tool support can make exceptions unsuitable in hard-real-time systems,
but please don't blindly trust "common wisdom" (e.g., unsupported statements about "efficiency");
but please don't naïvely trust "common wisdom" (e.g., unsupported statements about "efficiency");
such "wisdom" may be based on decades-old information or experienced from languages with very different properties than C++
(e.g., C or Java).
@ -21945,7 +21945,7 @@ Never allow an error to be reported from a destructor, a resource deallocation f
Here, copying `s` could throw, and if that throws and if `n`'s destructor then also throws, the program will exit via `std::terminate` because two exceptions can't be propagated simultaneously.
2. Classes with `Nefarious` members or bases are also hard to use safely, because their destructors must invoke `Nefarious`' destructor, and are similarly poisoned by its poor behavior:
2. Classes with `Nefarious` members or bases are also hard to use safely, because their destructors must invoke `Nefarious`' destructor, and are similarly poisoned by its bad behavior:
class Innocent_bystander {
@ -21955,7 +21955,7 @@ Never allow an error to be reported from a destructor, a resource deallocation f
void test(string& s)
{
Innocent_bystander i; // more trouble brewing
Innocent_bystander i; // more trouble brewing
string copy2 = s; // copy the string
} // destroy copy and then i