mirror of
https://github.com/isocpp/CppCoreGuidelines.git
synced 2025-12-17 20:54:41 +03:00
Fix typos and add internal links.
Two hours of semi-automatic digestion of the C++ Guidelines result in a host of small changes. Eight intermediate commits make up this squashed monster. First I ran 'aspell -l en_US -c CppCoreGuidelines.md' and interactively corrected several trivial typos. Then I spent a short hour inside Vim to improve the spacing by looking for '[a-z] [a-z]' plus the odd typo. Only after reading the 'how to contribute' section, I started to create smaller patches. Continuing by reading the .md-file on formatted form, I added a markdown link to the associated 'LICENSE' in the introduction. Then I scanned section 'SF' and fixed typos. Next I spotted a single problem with a French accent. After adding another internal link from the FAQ section to the Abstract, I finished the day by reading and correcting section CPL.
This commit is contained in:
@@ -10,7 +10,7 @@ Editors:
|
|||||||
This document is a very early draft. It is inkorrekt, incompleat, and pµøoorly formatted.
|
This document is a very early draft. It is inkorrekt, incompleat, and pµøoorly formatted.
|
||||||
Had it been an open source (code) project, this would have been release 0.6.
|
Had it been an open source (code) project, this would have been release 0.6.
|
||||||
Copying, use, modification, and creation of derivative works from this project is licensed under an MIT-style license.
|
Copying, use, modification, and creation of derivative works from this project is licensed under an MIT-style license.
|
||||||
Contributing to this project requires agreeing to a Contributor License. See the accompanying LICENSE file for details.
|
Contributing to this project requires agreeing to a Contributor License. See the accompanying [LICENSE](LICENSE) file for details.
|
||||||
We make this project available to "friendly users" to use, copy, modify, and derive from, hoping for constructive input.
|
We make this project available to "friendly users" to use, copy, modify, and derive from, hoping for constructive input.
|
||||||
|
|
||||||
Comments and suggestions for improvements are most welcome.
|
Comments and suggestions for improvements are most welcome.
|
||||||
@@ -966,7 +966,7 @@ Non-`const` global variables hide dependencies and make the dependencies subject
|
|||||||
|
|
||||||
void compute() // don't
|
void compute() // don't
|
||||||
{
|
{
|
||||||
// ...use data ...
|
// ... use data ...
|
||||||
}
|
}
|
||||||
|
|
||||||
void output() // don't
|
void output() // don't
|
||||||
@@ -3134,7 +3134,7 @@ You need a reason (use cases) for using a hierarchy.
|
|||||||
class Point1 {
|
class Point1 {
|
||||||
int x, y;
|
int x, y;
|
||||||
// ... operations ...
|
// ... operations ...
|
||||||
// .. no virtual functions ...
|
// ... no virtual functions ...
|
||||||
};
|
};
|
||||||
|
|
||||||
class Point2 {
|
class Point2 {
|
||||||
@@ -4213,7 +4213,7 @@ If the state of a base class object must depend on the state of a derived part o
|
|||||||
{
|
{
|
||||||
// ...
|
// ...
|
||||||
f(); // BAD: virtual call in constructor
|
f(); // BAD: virtual call in constructor
|
||||||
//...
|
// ...
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void f() = 0;
|
virtual void f() = 0;
|
||||||
@@ -4310,7 +4310,7 @@ The common action gets tedious to write and may accidentally not be common.
|
|||||||
|
|
||||||
##### Reason
|
##### Reason
|
||||||
|
|
||||||
If you need those constructors for a derived class, re-implementeing them is tedious and error prone.
|
If you need those constructors for a derived class, re-implementing them is tedious and error prone.
|
||||||
|
|
||||||
##### Example
|
##### Example
|
||||||
|
|
||||||
@@ -4656,7 +4656,7 @@ The ISO standard guarantees only a "valid but unspecified" state for the standar
|
|||||||
|
|
||||||
Here is a way to move a pointer without a test (imagine it as code in the implementation a move assignment):
|
Here is a way to move a pointer without a test (imagine it as code in the implementation a move assignment):
|
||||||
|
|
||||||
// move from other.oter to this->ptr
|
// move from other.ptr to this->ptr
|
||||||
T* temp = other.ptr;
|
T* temp = other.ptr;
|
||||||
other.ptr = nullptr;
|
other.ptr = nullptr;
|
||||||
delete ptr;
|
delete ptr;
|
||||||
@@ -4681,7 +4681,7 @@ A non-throwing move will be used more efficiently by standard-library and langua
|
|||||||
// ...
|
// ...
|
||||||
Vector(Vector&& a) noexcept :elem{a.elem}, sz{a.sz} { a.sz = 0; a.elem = nullptr; }
|
Vector(Vector&& a) noexcept :elem{a.elem}, sz{a.sz} { a.sz = 0; a.elem = nullptr; }
|
||||||
Vector& operator=(Vector&& a) noexcept { elem = a.elem; sz = a.sz; a.sz = 0; a.elem = nullptr; }
|
Vector& operator=(Vector&& a) noexcept { elem = a.elem; sz = a.sz; a.sz = 0; a.elem = nullptr; }
|
||||||
//...
|
// ...
|
||||||
public:
|
public:
|
||||||
T* elem;
|
T* elem;
|
||||||
int sz;
|
int sz;
|
||||||
@@ -4696,7 +4696,7 @@ These copy operations do not throw.
|
|||||||
// ...
|
// ...
|
||||||
Vector2(Vector2&& a) { *this = a; } // just use the copy
|
Vector2(Vector2&& a) { *this = a; } // just use the copy
|
||||||
Vector2& operator=(Vector2&& a) { *this = a; } // just use the copy
|
Vector2& operator=(Vector2&& a) { *this = a; } // just use the copy
|
||||||
//...
|
// ...
|
||||||
public:
|
public:
|
||||||
T* elem;
|
T* elem;
|
||||||
int sz;
|
int sz;
|
||||||
@@ -5629,7 +5629,7 @@ Flag all slicing.
|
|||||||
// ... use D's interface ...
|
// ... use D's interface ...
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// .. make do with B's interface ...
|
// ... make do with B's interface ...
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5694,7 +5694,7 @@ So, first make sure that your `dynamic_cast` really is as slow as you think it i
|
|||||||
and that your use of `dynamic_cast` is really performance critical.
|
and that your use of `dynamic_cast` is really performance critical.
|
||||||
|
|
||||||
We are of the opinion that current implementations of `dynamic_cast` are unnecessarily slow.
|
We are of the opinion that current implementations of `dynamic_cast` are unnecessarily slow.
|
||||||
For example, under sutitable conditions, it is possible to perform a `dynamic_cast` in [fast constant time](http://www.stroustrup.com/fast_dynamic_casting.pdf).
|
For example, under suitable conditions, it is possible to perform a `dynamic_cast` in [fast constant time](http://www.stroustrup.com/fast_dynamic_casting.pdf).
|
||||||
However, compatibility makes changes difficult even if all agree that an effort to optimize is worth while.
|
However, compatibility makes changes difficult even if all agree that an effort to optimize is worth while.
|
||||||
|
|
||||||
##### Enforcement
|
##### Enforcement
|
||||||
@@ -6399,14 +6399,14 @@ We can fix that problem by making ownership explicit:
|
|||||||
|
|
||||||
##### Note
|
##### Note
|
||||||
|
|
||||||
The fact that there are billions of lines of code that violates this rule against owning `T*`s cannot be ignored.
|
The fact that there are billions of lines of code that violate this rule against owning `T*`s cannot be ignored.
|
||||||
This code cannot all be rewritten (ever assuming good code transformation software).
|
This code cannot all be rewritten (ever assuming good code transformation software).
|
||||||
This problem cannot be solved (at scale) by transforming all owning pointer to `unique_ptr`s and `shared_ptr`s, partly because we need/use owning "raw pointers" in the implementation of our fundamental resource handles. For example, most `vector` implementations have one owning pointer and two non-owning pointers.
|
This problem cannot be solved (at scale) by transforming all owning pointer to `unique_ptr`s and `shared_ptr`s, partly because we need/use owning "raw pointers" in the implementation of our fundamental resource handles. For example, most `vector` implementations have one owning pointer and two non-owning pointers.
|
||||||
Also, many ABIs (and essentially all interfaces to C code) use `T*`s, some of them owning.
|
Also, many ABIs (and essentially all interfaces to C code) use `T*`s, some of them owning.
|
||||||
|
|
||||||
##### Note
|
##### Note
|
||||||
|
|
||||||
`owner<T>` has no default semantics beyond `T*` it can be used without changing any code using it and without affecting ABIs.
|
`owner<T>` has no default semantics beyond `T*`. It can be used without changing any code using it and without affecting ABIs.
|
||||||
It is simply a (most valuable) indicator to programmers and analysis tools.
|
It is simply a (most valuable) indicator to programmers and analysis tools.
|
||||||
For example, if an `owner<T>` is a member of a class, that class better have a destructor that `delete`s it.
|
For example, if an `owner<T>` is a member of a class, that class better have a destructor that `delete`s it.
|
||||||
|
|
||||||
@@ -6428,7 +6428,7 @@ Returning a (raw) pointer imposes a life-time management burden on the caller; t
|
|||||||
delete p;
|
delete p;
|
||||||
}
|
}
|
||||||
|
|
||||||
In addition to suffering from then problem from [leak](#???), this adds a spurious allocation and deallocation operation, and is needlessly verbose. If Gadget is cheap to move out of a function (i.e., is small or has an efficient move operation), just return it "by value:'
|
In addition to suffering from the problem from [leak](#???), this adds a spurious allocation and deallocation operation, and is needlessly verbose. If Gadget is cheap to move out of a function (i.e., is small or has an efficient move operation), just return it "by value:'
|
||||||
|
|
||||||
Gadget make_gadget(int n)
|
Gadget make_gadget(int n)
|
||||||
{
|
{
|
||||||
@@ -6443,7 +6443,7 @@ This rule applies to factory functions.
|
|||||||
|
|
||||||
##### Note
|
##### Note
|
||||||
|
|
||||||
If pointer semantics is required (e.g., because the return type needs to refer to a base class of a class hierarchy (an interface)), return a "smart pointer."
|
If pointer semantics are required (e.g., because the return type needs to refer to a base class of a class hierarchy (an interface)), return a "smart pointer."
|
||||||
|
|
||||||
##### Enforcement
|
##### Enforcement
|
||||||
|
|
||||||
@@ -6480,12 +6480,12 @@ See [the raw pointer rule](#Rr-ptr)
|
|||||||
##### Reason
|
##### Reason
|
||||||
|
|
||||||
A scoped object is a local object, a global object, or a member.
|
A scoped object is a local object, a global object, or a member.
|
||||||
This implies that there is no separate allocation and deallocation cost in excess that already used for the containing scope or object.
|
This implies that there is no separate allocation and deallocation cost in excess of that already used for the containing scope or object.
|
||||||
The members of a scoped object are themselves scoped and the scoped object's constructor and destructor manage the members' lifetimes.
|
The members of a scoped object are themselves scoped and the scoped object's constructor and destructor manage the members' lifetimes.
|
||||||
|
|
||||||
##### Example
|
##### Example
|
||||||
|
|
||||||
the following example is inefficient (because it has unnecessary allocation and deallocation), vulnerable to exception throws and returns in the "¦ part (leading to leaks), and verbose:
|
The following example is inefficient (because it has unnecessary allocation and deallocation), vulnerable to exception throws and returns in the "¦ part (leading to leaks), and verbose:
|
||||||
|
|
||||||
void some_function(int n)
|
void some_function(int n)
|
||||||
{
|
{
|
||||||
@@ -6516,13 +6516,13 @@ They are a notable source of errors.
|
|||||||
|
|
||||||
**Warning**: The initialization of global objects is not totally ordered. If you use a global object initialize it with a constant.
|
**Warning**: The initialization of global objects is not totally ordered. If you use a global object initialize it with a constant.
|
||||||
|
|
||||||
**Exception**: a global object is often better than a singleton.
|
**Exception**: A global object is often better than a singleton.
|
||||||
|
|
||||||
**Exception**: An immutable (`const`) global does not introduce the problems we try to avoid by banning global objects.
|
**Exception**: An immutable (`const`) global does not introduce the problems we try to avoid by banning global objects.
|
||||||
|
|
||||||
##### Enforcement
|
##### Enforcement
|
||||||
|
|
||||||
(??? NM: Obviously we can warn about non-`const` statics....do we want to?)
|
(??? NM: Obviously we can warn about non-`const` statics ... do we want to?)
|
||||||
|
|
||||||
## <a name="SS-alloc"></a> R.alloc: Allocation and deallocation
|
## <a name="SS-alloc"></a> R.alloc: Allocation and deallocation
|
||||||
|
|
||||||
@@ -6563,9 +6563,9 @@ In some implementations that `delete` and that `free()` might work, or maybe the
|
|||||||
##### Exception
|
##### Exception
|
||||||
|
|
||||||
There are applications and sections of code where exceptions are not acceptable.
|
There are applications and sections of code where exceptions are not acceptable.
|
||||||
Some of the best such example are in life-critical hard real-time code.
|
Some of the best such examples are in life-critical hard real-time code.
|
||||||
Beware that many bans on exception use are based on superstition (bad)
|
Beware that many bans on exception use are based on superstition (bad)
|
||||||
or by concerns for older code bases with unsystematics resource management (unfortunately, but sometimes necessary).
|
or by concerns for older code bases with unsystematic resource management (unfortunately, but sometimes necessary).
|
||||||
In such cases, consider the `nothrow` versions of `new`.
|
In such cases, consider the `nothrow` versions of `new`.
|
||||||
|
|
||||||
##### Enforcement
|
##### Enforcement
|
||||||
@@ -6577,7 +6577,7 @@ Flag explicit use of `malloc` and `free`.
|
|||||||
##### Reason
|
##### Reason
|
||||||
|
|
||||||
The pointer returned by `new` should belong to a resource handle (that can call `delete`).
|
The pointer returned by `new` should belong to a resource handle (that can call `delete`).
|
||||||
If the pointer returned from `new` is assigned to a plain/naked pointer, the object can be leaked.
|
If the pointer returned by `new` is assigned to a plain/naked pointer, the object can be leaked.
|
||||||
|
|
||||||
##### Note
|
##### Note
|
||||||
|
|
||||||
@@ -6827,7 +6827,7 @@ A function that does not manipulate lifetime should take raw pointers or referen
|
|||||||
};
|
};
|
||||||
|
|
||||||
// caller
|
// caller
|
||||||
shared_ptr<widget> my_widget = /*...*/;
|
shared_ptr<widget> my_widget = /* ... */;
|
||||||
f(my_widget);
|
f(my_widget);
|
||||||
|
|
||||||
widget stack_widget;
|
widget stack_widget;
|
||||||
@@ -6844,7 +6844,7 @@ A function that does not manipulate lifetime should take raw pointers or referen
|
|||||||
};
|
};
|
||||||
|
|
||||||
// caller
|
// caller
|
||||||
shared_ptr<widget> my_widget = /*...*/;
|
shared_ptr<widget> my_widget = /* ... */;
|
||||||
f(*my_widget);
|
f(*my_widget);
|
||||||
|
|
||||||
widget stack_widget;
|
widget stack_widget;
|
||||||
@@ -7015,7 +7015,7 @@ To do this, sometimes you need to take a local copy of a smart pointer, which fi
|
|||||||
|
|
||||||
Consider this code:
|
Consider this code:
|
||||||
|
|
||||||
// global (static or heap), or aliased local...
|
// global (static or heap), or aliased local ...
|
||||||
shared_ptr<widget> g_p = ...;
|
shared_ptr<widget> g_p = ...;
|
||||||
|
|
||||||
void f(widget& w)
|
void f(widget& w)
|
||||||
@@ -7026,7 +7026,7 @@ Consider this code:
|
|||||||
|
|
||||||
void g()
|
void g()
|
||||||
{
|
{
|
||||||
g_p = ... ; // oops, if this was the last shared_ptr to that widget, destroys the widget
|
g_p = ...; // oops, if this was the last shared_ptr to that widget, destroys the widget
|
||||||
}
|
}
|
||||||
|
|
||||||
The following should not pass code review:
|
The following should not pass code review:
|
||||||
@@ -7214,7 +7214,7 @@ Readability. Minimize resource retention. Avoid accidental misuse of value.
|
|||||||
for (int i = 0; i < 20; ++i) { /* ... */ } // good: i is local to for-loop
|
for (int i = 0; i < 20; ++i) { /* ... */ } // good: i is local to for-loop
|
||||||
|
|
||||||
if (auto pc = dynamic_cast<Circle*>(ps)) { // good: pc is local to if-statement
|
if (auto pc = dynamic_cast<Circle*>(ps)) { // good: pc is local to if-statement
|
||||||
// ...deal with Circle ...
|
// ... deal with Circle ...
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// ... handle error ...
|
// ... handle error ...
|
||||||
@@ -7234,7 +7234,7 @@ Readability. Minimize resource retention. Avoid accidental misuse of value.
|
|||||||
|
|
||||||
This function is by most measure too long anyway, but the point is that the used by `fn` and the file handle held by `is`
|
This function is by most measure too long anyway, but the point is that the used by `fn` and the file handle held by `is`
|
||||||
are retained for much longer than needed and that unanticipated use of `is` and `fn` could happen later in the function.
|
are retained for much longer than needed and that unanticipated use of `is` and `fn` could happen later in the function.
|
||||||
In this case, it might be a good ide to factor out the read:
|
In this case, it might be a good idea to factor out the read:
|
||||||
|
|
||||||
void fill_record(Record& r, const string& name)
|
void fill_record(Record& r, const string& name)
|
||||||
{
|
{
|
||||||
@@ -7272,11 +7272,11 @@ Readability. Minimize resource retention.
|
|||||||
v.push_back(s);
|
v.push_back(s);
|
||||||
|
|
||||||
for (int i = 0; i < 20; ++i) { // good: i is local to for-loop
|
for (int i = 0; i < 20; ++i) { // good: i is local to for-loop
|
||||||
//* ...
|
// ...
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto pc = dynamic_cast<Circle*>(ps)) { // good: pc is local to if-statement
|
if (auto pc = dynamic_cast<Circle*>(ps)) { // good: pc is local to if-statement
|
||||||
// ...deal with Circle ...
|
// ... deal with Circle ...
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// ... handle error ...
|
// ... handle error ...
|
||||||
@@ -7618,7 +7618,7 @@ A good optimizer should know about input operations and eliminate the redundant
|
|||||||
|
|
||||||
##### Example
|
##### Example
|
||||||
|
|
||||||
Using an `unitialized` value is a symptom of a problem and not a solution:
|
Using an `uninitialized` value is a symptom of a problem and not a solution:
|
||||||
|
|
||||||
widget i = uninit; // bad
|
widget i = uninit; // bad
|
||||||
widget j = uninit;
|
widget j = uninit;
|
||||||
@@ -7636,7 +7636,7 @@ Using an `unitialized` value is a symptom of a problem and not a solution:
|
|||||||
j = f4();
|
j = f4();
|
||||||
}
|
}
|
||||||
|
|
||||||
Now the compiler cannot even simply detect a used-befor-set.
|
Now the compiler cannot even simply detect a used-before-set.
|
||||||
|
|
||||||
##### Note
|
##### Note
|
||||||
|
|
||||||
@@ -8664,7 +8664,7 @@ It makes a lie out of `const`.
|
|||||||
##### Note
|
##### Note
|
||||||
|
|
||||||
Usually the reason to "cast away `const`" is to allow the updating of some transient information of an otherwise immutable object.
|
Usually the reason to "cast away `const`" is to allow the updating of some transient information of an otherwise immutable object.
|
||||||
Examples are cashing, mnemorization, and precomputation.
|
Examples are cashing, memorization, and precomputation.
|
||||||
Such examples are often handled as well or better using `mutable` or an indirection than with a `const_cast`.
|
Such examples are often handled as well or better using `mutable` or an indirection than with a `const_cast`.
|
||||||
|
|
||||||
##### Example
|
##### Example
|
||||||
@@ -9133,7 +9133,7 @@ Concurrency rule summary:
|
|||||||
Speaking of concurrency, should there be a note about the dangers of `std::atomic` (weapons)?
|
Speaking of concurrency, should there be a note about the dangers of `std::atomic` (weapons)?
|
||||||
A lot of people, myself included, like to experiment with `std::memory_order`, but it is perhaps best to keep a close watch on those things in production code.
|
A lot of people, myself included, like to experiment with `std::memory_order`, but it is perhaps best to keep a close watch on those things in production code.
|
||||||
Even vendors mess this up: Microsoft had to fix their `shared_ptr` (weak refcount decrement wasn't synchronized-with the destructor, if I recall correctly, although it was only a problem on ARM, not Intel)
|
Even vendors mess this up: Microsoft had to fix their `shared_ptr` (weak refcount decrement wasn't synchronized-with the destructor, if I recall correctly, although it was only a problem on ARM, not Intel)
|
||||||
and everyone (gcc, clang, Microsoft, and intel) had to fix their `compare_exchange_*` this year, after an implementation bug caused losses to some finance company and they were kind enough to let the community know.
|
and everyone (gcc, clang, Microsoft, and Intel) had to fix their `compare_exchange_*` this year, after an implementation bug caused losses to some finance company and they were kind enough to let the community know.
|
||||||
|
|
||||||
It should definitely be mentioned that `volatile` does not provide atomicity, does not synchronize between threads, and does not prevent instruction reordering (neither compiler nor hardware), and simply has nothing to do with concurrency.
|
It should definitely be mentioned that `volatile` does not provide atomicity, does not synchronize between threads, and does not prevent instruction reordering (neither compiler nor hardware), and simply has nothing to do with concurrency.
|
||||||
|
|
||||||
@@ -11000,7 +11000,7 @@ Assume that `Apple` and `Pear` are two kinds of `Fruit`s.
|
|||||||
Apple& a0 = &aa[0]; // a Pear?
|
Apple& a0 = &aa[0]; // a Pear?
|
||||||
Apple& a1 = &aa[1]; // a Pear?
|
Apple& a1 = &aa[1]; // a Pear?
|
||||||
|
|
||||||
Probably, `aa[0]` will be a `Pear` (without the use af a cast!).
|
Probably, `aa[0]` will be a `Pear` (without the use of a cast!).
|
||||||
If `sizeof(Apple) != sizeof(Pear)` the access to `aa[1]` will not be aligned to the proper start of an object in the array.
|
If `sizeof(Apple) != sizeof(Pear)` the access to `aa[1]` will not be aligned to the proper start of an object in the array.
|
||||||
We have a type violation and possibly (probably) a memory corruption.
|
We have a type violation and possibly (probably) a memory corruption.
|
||||||
Never write such code.
|
Never write such code.
|
||||||
@@ -11505,7 +11505,7 @@ That subset can be compiled with both C and C++ compilers, and when compiled as
|
|||||||
|
|
||||||
##### Reason
|
##### Reason
|
||||||
|
|
||||||
C++ is more expressive than C and offer better support for many types of programming.
|
C++ is more expressive than C and offers better support for many types of programming.
|
||||||
|
|
||||||
##### Example
|
##### Example
|
||||||
|
|
||||||
@@ -11543,7 +11543,7 @@ None needed
|
|||||||
|
|
||||||
# <a name="S-source"></a> SF: Source files
|
# <a name="S-source"></a> SF: Source files
|
||||||
|
|
||||||
Distinguish between declarations (used as interfaces) and definitions (used as implementations)
|
Distinguish between declarations (used as interfaces) and definitions (used as implementations).
|
||||||
Use header files to represent interfaces and to emphasize logical structure.
|
Use header files to represent interfaces and to emphasize logical structure.
|
||||||
|
|
||||||
Source file rule summary:
|
Source file rule summary:
|
||||||
@@ -11825,8 +11825,8 @@ It is almost always a bug to mention an unnamed namespace in a header file.
|
|||||||
|
|
||||||
##### Reason
|
##### Reason
|
||||||
|
|
||||||
nothing external can depend on an entity in a nested unnamed namespace.
|
Nothing external can depend on an entity in a nested unnamed namespace.
|
||||||
Consider putting every definition in an implementation source file should be in an unnamed namespace unless that is defining an "external/exported" entity.
|
Consider putting every definition in an implementation source file in an unnamed namespace unless that is defining an "external/exported" entity.
|
||||||
|
|
||||||
##### Example
|
##### Example
|
||||||
|
|
||||||
@@ -11933,9 +11933,9 @@ Many
|
|||||||
* see "stopping programmers from doing unusual things" as their primary aim
|
* see "stopping programmers from doing unusual things" as their primary aim
|
||||||
* aim at portability across many compilers (some 10 years old)
|
* aim at portability across many compilers (some 10 years old)
|
||||||
* are written to preserve decades old code bases
|
* are written to preserve decades old code bases
|
||||||
* aims at a single application domain
|
* aim at a single application domain
|
||||||
* are downright counterproductive
|
* are downright counterproductive
|
||||||
* are ignored (must be ignored for programmers to get their work done well)
|
* are ignored (must be ignored by programmers to get their work done well)
|
||||||
|
|
||||||
A bad coding standard is worse than no coding standard.
|
A bad coding standard is worse than no coding standard.
|
||||||
However an appropriate set of guidelines are much better than no standards: "Form is liberating."
|
However an appropriate set of guidelines are much better than no standards: "Form is liberating."
|
||||||
@@ -11983,7 +11983,7 @@ Reference sections:
|
|||||||
Any similarities to this set of guidelines are unsurprising because Bjarne Stroustrup was an author of JSF++.
|
Any similarities to this set of guidelines are unsurprising because Bjarne Stroustrup was an author of JSF++.
|
||||||
Recommended, but note its very specific focus.
|
Recommended, but note its very specific focus.
|
||||||
* [Mozilla Portability Guide](https://developer.mozilla.org/en-US/docs/Mozilla/C%2B%2B_Portability_Guide).
|
* [Mozilla Portability Guide](https://developer.mozilla.org/en-US/docs/Mozilla/C%2B%2B_Portability_Guide).
|
||||||
As the name indicate, this aims for portability across many (old) compilers.
|
As the name indicates, this aims for portability across many (old) compilers.
|
||||||
As such, it is restrictive.
|
As such, it is restrictive.
|
||||||
* [Geosoft.no: C++ Programming Style Guidelines](http://geosoft.no/development/cppstyle.html).
|
* [Geosoft.no: C++ Programming Style Guidelines](http://geosoft.no/development/cppstyle.html).
|
||||||
???.
|
???.
|
||||||
@@ -12025,8 +12025,7 @@ Reference sections:
|
|||||||
* [isocpp.org](http://www.isocpp.com)
|
* [isocpp.org](http://www.isocpp.com)
|
||||||
* [Bjarne Stroustrup's home pages](http://www.stroustrup.com)
|
* [Bjarne Stroustrup's home pages](http://www.stroustrup.com)
|
||||||
* [WG21](http://www.open-std.org/jtc1/sc22/wg21/)
|
* [WG21](http://www.open-std.org/jtc1/sc22/wg21/)
|
||||||
* <a name="Boost"></a>
|
* [Boost](http://www.boost.org)<a name="Boost"></a>
|
||||||
[Boost](http://www.boost.org)
|
|
||||||
* [Adobe open source](http://www.adobe.com/open-source.html)
|
* [Adobe open source](http://www.adobe.com/open-source.html)
|
||||||
* [Poco libraries](http://pocoproject.org/)
|
* [Poco libraries](http://pocoproject.org/)
|
||||||
|
|
||||||
@@ -12451,7 +12450,7 @@ Issue a diagnostic for any indexing expression on an expression or variable of a
|
|||||||
|
|
||||||
void f(int i, int j)
|
void f(int i, int j)
|
||||||
{
|
{
|
||||||
a[i + j] = 12; // BAD, could be rewritten as...
|
a[i + j] = 12; // BAD, could be rewritten as ...
|
||||||
at(a, i + j) = 12; // OK - bounds-checked
|
at(a, i + j) = 12; // OK - bounds-checked
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -12927,7 +12926,7 @@ Too much space makes the text larger and distracts.
|
|||||||
|
|
||||||
##### Note
|
##### Note
|
||||||
|
|
||||||
Some IDEs have their own opinions and adds distracting space.
|
Some IDEs have their own opinions and add distracting space.
|
||||||
|
|
||||||
##### Note
|
##### Note
|
||||||
|
|
||||||
@@ -13071,11 +13070,11 @@ This section covers answers to frequently asked questions about these guidelines
|
|||||||
|
|
||||||
### <a name="Faq-aims"></a> FAQ.1: What do these guidelines aim to achieve?
|
### <a name="Faq-aims"></a> FAQ.1: What do these guidelines aim to achieve?
|
||||||
|
|
||||||
See the top of this page. This is an open source project to maintain modern authoritative guidelines for writing C++ code using the current C++ Standard (as of this writing, C++14). The guidelines are designed to be modern, machine-enforceable wherever possible, and open to contributions and forking so that organizations can easily incorporate them into their own corporate coding guidelines.
|
See the <a href="#S-abstract">top of this page</a>. This is an open source project to maintain modern authoritative guidelines for writing C++ code using the current C++ Standard (as of this writing, C++14). The guidelines are designed to be modern, machine-enforceable wherever possible, and open to contributions and forking so that organizations can easily incorporate them into their own corporate coding guidelines.
|
||||||
|
|
||||||
### <a name="Faq-announced"></a> FAQ.2: When and where was this work first announced?
|
### <a name="Faq-announced"></a> FAQ.2: When and where was this work first announced?
|
||||||
|
|
||||||
It was announced by [Bjarne Stroustrup in his CppCon 2015 opening keynote, “Writing Good C++14”](https://isocpp.org/blog/2015/09/stroustrup-cppcon15-keynote). See also the [accompanying isocpp.org blog post](https://isocpp.org/blog/2015/09/bjarne-stroustrup-announces-cpp-core-guidelines), and for the rationale of the type and memory safety guidelines see [Herb Sutter’s follow-up CppCon 2015 talk, “Writing Good C++14... By Default”](https://isocpp.org/blog/2015/09/sutter-cppcon15-day2plenary).
|
It was announced by [Bjarne Stroustrup in his CppCon 2015 opening keynote, “Writing Good C++14”](https://isocpp.org/blog/2015/09/stroustrup-cppcon15-keynote). See also the [accompanying isocpp.org blog post](https://isocpp.org/blog/2015/09/bjarne-stroustrup-announces-cpp-core-guidelines), and for the rationale of the type and memory safety guidelines see [Herb Sutter’s follow-up CppCon 2015 talk, “Writing Good C++14 ... By Default”](https://isocpp.org/blog/2015/09/sutter-cppcon15-day2plenary).
|
||||||
|
|
||||||
### <a name="Faq-maintainers"></a> FAQ.3: Who are the authors and maintainers of these guidelines?
|
### <a name="Faq-maintainers"></a> FAQ.3: Who are the authors and maintainers of these guidelines?
|
||||||
|
|
||||||
@@ -13246,7 +13245,7 @@ Here is an example of the last option:
|
|||||||
|
|
||||||
class B {
|
class B {
|
||||||
public:
|
public:
|
||||||
B() { /* ... */ f(); /*...*/ } // BAD: see Item 49.1
|
B() { /* ... */ f(); /* ... */ } // BAD: see Item 49.1
|
||||||
|
|
||||||
virtual void f() = 0;
|
virtual void f() = 0;
|
||||||
|
|
||||||
@@ -13257,7 +13256,7 @@ Here is an example of the last option:
|
|||||||
protected:
|
protected:
|
||||||
B() { /* ... */ }
|
B() { /* ... */ }
|
||||||
virtual void PostInitialize() // called right after construction
|
virtual void PostInitialize() // called right after construction
|
||||||
{ /* ... */ f(); /*...*/ } // GOOD: virtual dispatch is safe
|
{ /* ... */ f(); /* ... */ } // GOOD: virtual dispatch is safe
|
||||||
public:
|
public:
|
||||||
virtual void f() = 0;
|
virtual void f() = 0;
|
||||||
|
|
||||||
@@ -13301,7 +13300,7 @@ The common case for a base class is that it's intended to have publicly derived
|
|||||||
// ...
|
// ...
|
||||||
};
|
};
|
||||||
|
|
||||||
class derived : public base { /*...*/ };
|
class derived : public base { /* ... */ };
|
||||||
|
|
||||||
{
|
{
|
||||||
shared_ptr<base> pb = make_shared<derived>();
|
shared_ptr<base> pb = make_shared<derived>();
|
||||||
@@ -13319,7 +13318,7 @@ In rarer cases, such as policy classes, the class is used as a base class for co
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<class Policy>
|
template<class Policy>
|
||||||
class customizable : Policy { /*...*/ }; // note: private inheritance
|
class customizable : Policy { /* ... */ }; // note: private inheritance
|
||||||
|
|
||||||
##### Note
|
##### Note
|
||||||
|
|
||||||
@@ -13414,7 +13413,7 @@ Never allow an error to be reported from a destructor, a resource deallocation f
|
|||||||
std::array<nefarious, 10> arr; // this line can std::terminate(!)
|
std::array<nefarious, 10> arr; // this line can std::terminate(!)
|
||||||
}
|
}
|
||||||
|
|
||||||
The behavior of arrays is undefined in the presence of destructors that throw because there is no reasonable rollback behavior that could ever be devised. Just think: What code can the compiler generate for constructing an `arr` where, if the fourth object's constructor throws, the code has to give up and in its cleanup mode tries to call the destructors of the already-constructed objects... and one or more of those destructors throws? There is no satisfactory answer.
|
The behavior of arrays is undefined in the presence of destructors that throw because there is no reasonable rollback behavior that could ever be devised. Just think: What code can the compiler generate for constructing an `arr` where, if the fourth object's constructor throws, the code has to give up and in its cleanup mode tries to call the destructors of the already-constructed objects ... and one or more of those destructors throws? There is no satisfactory answer.
|
||||||
|
|
||||||
5. You can't use `Nefarious` objects in standard containers:
|
5. You can't use `Nefarious` objects in standard containers:
|
||||||
|
|
||||||
@@ -13770,7 +13769,7 @@ A relatively informal definition of terms used in the guidelines
|
|||||||
Thus, to produce acceptable code, we sometimes have to do more than just follow the formal specification.
|
Thus, to produce acceptable code, we sometimes have to do more than just follow the formal specification.
|
||||||
* *cost*: the expense (e.g., in programmer time, run time, or space) of producing a program or of executing it.
|
* *cost*: the expense (e.g., in programmer time, run time, or space) of producing a program or of executing it.
|
||||||
Ideally, cost should be a function of complexity.
|
Ideally, cost should be a function of complexity.
|
||||||
* *customisation point*: ???
|
* *customization point*: ???
|
||||||
* *data*: values used in a computation.
|
* *data*: values used in a computation.
|
||||||
* *debugging*: the act of searching for and removing errors from a program; usually far less systematic than testing.
|
* *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.
|
* *declaration*: the specification of a name with its type in a program.
|
||||||
@@ -13882,11 +13881,11 @@ Alternatively, we will decide that no change is needed and delete the entry.
|
|||||||
* Should physical design (what's in a file) and large-scale design (libraries, groups of libraries) be addressed?
|
* Should physical design (what's in a file) and large-scale design (libraries, groups of libraries) be addressed?
|
||||||
* Namespaces
|
* Namespaces
|
||||||
* How granular should namespaces be? All classes/functions designed to work together and released together (as defined in Sutter/Alexandrescu) or something narrower or wider?
|
* How granular should namespaces be? All classes/functions designed to work together and released together (as defined in Sutter/Alexandrescu) or something narrower or wider?
|
||||||
* Should there be inline namespaces (a-la `std::literals::*_literals`)?
|
* Should there be inline namespaces (à la `std::literals::*_literals`)?
|
||||||
* Avoid implicit conversions
|
* 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 its called "¦ argh
|
* Const member functions should be thread safe "¦ aka, but I don't really change the variable, just assign it a value the first time its called "¦ argh
|
||||||
* Always initialize variables, use initialization lists for member variables.
|
* 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 favourite 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 `const`'ness wherever possible: member functions, variables and (yippee) `const_iterators`
|
||||||
* Use `auto`
|
* Use `auto`
|
||||||
* `(size)` vs. `{initializers}` vs. `{Extent{size}}`
|
* `(size)` vs. `{initializers}` vs. `{Extent{size}}`
|
||||||
@@ -13920,7 +13919,7 @@ Alternatively, we will decide that no change is needed and delete the entry.
|
|||||||
|
|
||||||
* Use RAII lock guards (`lock_guard`, `unique_lock`, `shared_lock`), never call `mutex.lock` and `mutex.unlock` directly (RAII)
|
* Use RAII lock guards (`lock_guard`, `unique_lock`, `shared_lock`), never call `mutex.lock` and `mutex.unlock` directly (RAII)
|
||||||
* Prefer non-recursive locks (often used to work around bad reasoning, overhead)
|
* Prefer non-recursive locks (often used to work around bad reasoning, overhead)
|
||||||
* Join your threads! (because of `std::terminate` in destructor if not joined or detached... is there a good reason to detach threads?) -- ??? could support library provide a RAII wrapper for `std::thread`?
|
* Join your threads! (because of `std::terminate` in destructor if not joined or detached ... is there a good reason to detach threads?) -- ??? could support library provide a RAII wrapper for `std::thread`?
|
||||||
* If two or more mutexes must be acquired at the same time, use `std::lock` (or another deadlock avoidance algorithm?)
|
* If two or more mutexes must be acquired at the same time, use `std::lock` (or another deadlock avoidance algorithm?)
|
||||||
* 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.
|
* 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)
|
* 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)
|
||||||
|
|||||||
Reference in New Issue
Block a user