Skip to content

Commit 864a9c6

Browse files
authored
Merge pull request #11 from bgloyer/master
merge master
2 parents e0d2694 + 4b8b281 commit 864a9c6

File tree

3 files changed

+96
-76
lines changed

3 files changed

+96
-76
lines changed

CppCoreGuidelines.md

Lines changed: 91 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# <a name="main"></a>C++ Core Guidelines
22

3-
January 3, 2022
3+
July 13, 2022
44

55

66
Editors:
@@ -52,7 +52,7 @@ Supporting sections:
5252
* [RF: References](#S-references)
5353
* [Pro: Profiles](#S-profile)
5454
* [GSL: Guidelines support library](#S-gsl)
55-
* [NL: Naming and layout rules](#S-naming)
55+
* [NL: Naming and layout suggestions](#S-naming)
5656
* [FAQ: Answers to frequently asked questions](#S-faq)
5757
* [Appendix A: Libraries](#S-libraries)
5858
* [Appendix B: Modernizing code](#S-modernizing)
@@ -445,7 +445,7 @@ Supporting sections:
445445
* [RF: References](#S-references)
446446
* [Pro: Profiles](#S-profile)
447447
* [GSL: Guidelines support library](#S-gsl)
448-
* [NL: Naming and layout rules](#S-naming)
448+
* [NL: Naming and layout suggestions](#S-naming)
449449
* [FAQ: Answers to frequently asked questions](#S-faq)
450450
* [Appendix A: Libraries](#S-libraries)
451451
* [Appendix B: Modernizing code](#S-modernizing)
@@ -2432,7 +2432,6 @@ Naming that lambda breaks up the expression into its logical parts and provides
24322432
auto lessT = [](T x, T y) { return x.rank() < y.rank() && x.value() < y.value(); };
24332433

24342434
sort(a, b, lessT);
2435-
find_if(a, b, lessT);
24362435

24372436
The shortest code is not always the best for performance or maintainability.
24382437

@@ -2927,31 +2926,11 @@ For advanced uses (only), where you really need to optimize for rvalues passed t
29272926

29282927
void sink(unique_ptr<widget>); // input only, and moves ownership of the widget
29292928

2930-
Avoid "esoteric techniques" such as:
2931-
2932-
* Passing arguments as `T&&` "for efficiency".
2933-
Most rumors about performance advantages from passing by `&&` are false or brittle (but see [F.18](#Rf-consume) and [F.19](#Rf-forward)).
2934-
* Returning `const T&` from assignments and similar operations (see [F.47](#Rf-assignment-op).)
2935-
2936-
##### Example
2937-
2938-
Assuming that `Matrix` has move operations (possibly by keeping its elements in a `std::vector`):
2939-
2940-
Matrix operator+(const Matrix& a, const Matrix& b)
2941-
{
2942-
Matrix res;
2943-
// ... fill res with the sum ...
2944-
return res;
2945-
}
2946-
2947-
Matrix x = m1 + m2; // move constructor
2948-
2949-
y = m3 + m3; // move assignment
2929+
Avoid "esoteric techniques" such as passing arguments as `T&&` "for efficiency".
2930+
Most rumors about performance advantages from passing by `&&` are false or brittle (but see [F.18](#Rf-consume) and [F.19](#Rf-forward)).
29502931

29512932
##### Notes
29522933

2953-
The return value optimization doesn't handle the assignment case, but the move assignment does.
2954-
29552934
A reference can be assumed to refer to a valid object (language rule).
29562935
There is no (legitimate) "null reference."
29572936
If you need the notion of an optional value, use a pointer, `std::optional`, or a special value used to denote "no value."
@@ -3104,6 +3083,26 @@ The argument against is that it prevents (very frequent) use of move semantics.
31043083
* If a type is expensive to move (e.g., `array<BigPOD>`), consider allocating it on the free store and return a handle (e.g., `unique_ptr`), or passing it in a reference to non-`const` target object to fill (to be used as an out-parameter).
31053084
* To reuse an object that carries capacity (e.g., `std::string`, `std::vector`) across multiple calls to the function in an inner loop: [treat it as an in/out parameter and pass by reference](#Rf-out-multi).
31063085

3086+
##### Example
3087+
3088+
Assuming that `Matrix` has move operations (possibly by keeping its elements in a `std::vector`):
3089+
3090+
Matrix operator+(const Matrix& a, const Matrix& b)
3091+
{
3092+
Matrix res;
3093+
// ... fill res with the sum ...
3094+
return res;
3095+
}
3096+
3097+
Matrix x = m1 + m2; // move constructor
3098+
3099+
y = m3 + m3; // move assignment
3100+
3101+
3102+
##### Note
3103+
3104+
The return value optimization doesn't handle the assignment case, but the move assignment does.
3105+
31073106
##### Example
31083107

31093108
struct Package { // exceptional case: expensive-to-move object
@@ -3230,6 +3229,39 @@ Another example, use a specific type along the lines of `variant<T, error_code>`
32303229
* Output parameters should be replaced by return values.
32313230
An output parameter is one that the function writes to, invokes a non-`const` member function, or passes on as a non-`const`.
32323231

3232+
### <a name="Rf-ptr-ref"></a>F.60: Prefer `T*` over `T&` when "no argument" is a valid option
3233+
3234+
##### Reason
3235+
3236+
A pointer (`T*`) can be a `nullptr` and a reference (`T&`) cannot, there is no valid "null reference".
3237+
Sometimes having `nullptr` as an alternative to indicated "no object" is useful, but if it is not, a reference is notationally simpler and might yield better code.
3238+
3239+
##### Example
3240+
3241+
string zstring_to_string(zstring p) // zstring is a char*; that is a C-style string
3242+
{
3243+
if (!p) return string{}; // p might be nullptr; remember to check
3244+
return string{p};
3245+
}
3246+
3247+
void print(const vector<int>& r)
3248+
{
3249+
// r refers to a vector<int>; no check needed
3250+
}
3251+
3252+
##### Note
3253+
3254+
It is possible, but not valid C++ to construct a reference that is essentially a `nullptr` (e.g., `T* p = nullptr; T& r = *p;`).
3255+
That error is very uncommon.
3256+
3257+
##### Note
3258+
3259+
If you prefer the pointer notation (`->` and/or `*` vs. `.`), `not_null<T*>` provides the same guarantee as `T&`.
3260+
3261+
##### Enforcement
3262+
3263+
* Flag ???
3264+
32333265
### <a name="Rf-ptr"></a>F.22: Use `T*` or `owner<T*>` to designate a single object
32343266

32353267
##### Reason
@@ -3468,39 +3500,6 @@ Have a single object own the shared object (e.g. a scoped object) and destroy th
34683500

34693501
(Not enforceable) This is a too complex pattern to reliably detect.
34703502

3471-
### <a name="Rf-ptr-ref"></a>F.60: Prefer `T*` over `T&` when "no argument" is a valid option
3472-
3473-
##### Reason
3474-
3475-
A pointer (`T*`) can be a `nullptr` and a reference (`T&`) cannot, there is no valid "null reference".
3476-
Sometimes having `nullptr` as an alternative to indicated "no object" is useful, but if it is not, a reference is notationally simpler and might yield better code.
3477-
3478-
##### Example
3479-
3480-
string zstring_to_string(zstring p) // zstring is a char*; that is a C-style string
3481-
{
3482-
if (!p) return string{}; // p might be nullptr; remember to check
3483-
return string{p};
3484-
}
3485-
3486-
void print(const vector<int>& r)
3487-
{
3488-
// r refers to a vector<int>; no check needed
3489-
}
3490-
3491-
##### Note
3492-
3493-
It is possible, but not valid C++ to construct a reference that is essentially a `nullptr` (e.g., `T* p = nullptr; T& r = *p;`).
3494-
That error is very uncommon.
3495-
3496-
##### Note
3497-
3498-
If you prefer the pointer notation (`->` and/or `*` vs. `.`), `not_null<T*>` provides the same guarantee as `T&`.
3499-
3500-
##### Enforcement
3501-
3502-
* Flag ???
3503-
35043503
### <a name="Rf-return-ptr"></a>F.42: Return a `T*` to indicate a position (only)
35053504

35063505
##### Reason
@@ -4477,7 +4476,7 @@ For example, a derived class might be allowed to skip a run-time check because i
44774476

44784477
##### Note
44794478

4480-
Prefer the order `public` members before `protected` members before `private` members [see](#Rl-order).
4479+
Prefer the order `public` members before `protected` members before `private` members; see [NL.16](#Rl-order).
44814480

44824481
##### Enforcement
44834482

@@ -4993,12 +4992,18 @@ There is a lot of code that is non-specific about ownership.
49934992

49944993
##### Example
49954994

4996-
???
4995+
class legacy_class
4996+
{
4997+
foo* m_owning; // Bad: change to unique_ptr<T> or owner<T*>
4998+
bar* m_observer; // OK: keep
4999+
}
5000+
5001+
The only way to determine ownership may be code analysis.
49975002

49985003
##### Note
49995004

5000-
If the `T*` or `T&` is owning, mark it `owning`. If the `T*` is not owning, consider marking it `ptr`.
5001-
This will aid documentation and analysis.
5005+
Ownership should be clear in new code (and refactored legacy code) according to [R.20](#Rr-owner) for owning
5006+
pointers and [R.3](#Rr-ptr) for non-owning pointers. References should never own [R.4](#Rr-ref).
50025007

50035008
##### Enforcement
50045009

@@ -8434,7 +8439,7 @@ Many parts of the C++ semantics assume its default meaning.
84348439

84358440
If you "mess with" operator `&` be sure that its definition has matching meanings for `->`, `[]`, `*`, and `.` on the result type.
84368441
Note that operator `.` currently cannot be overloaded so a perfect system is impossible.
8437-
We hope to remedy that: <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4477.pdf>.
8442+
We hope to remedy that: [Operator Dot (R2)](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4477.pdf).
84388443
Note that `std::addressof()` always yields a built-in pointer.
84398444

84408445
##### Enforcement
@@ -15623,7 +15628,7 @@ Error-handling rule summary:
1562315628
* [E.13: Never throw while being the direct owner of an object](#Re-never-throw)
1562415629
* [E.14: Use purpose-designed user-defined types as exceptions (not built-in types)](#Re-exception-types)
1562515630
* [E.15: Throw by value, catch exceptions from a hierarchy by reference](#Re-exception-ref)
15626-
* [E.16: Destructors, deallocation, and `swap` must never fail](#Re-never-fail)
15631+
* [E.16: Destructors, deallocation, `swap`, and exception type copy/move construction must never fail](#Re-never-fail)
1562715632
* [E.17: Don't try to catch every exception in every function](#Re-not-always)
1562815633
* [E.18: Minimize the use of explicit `try`/`catch`](#Re-catch)
1562915634
* [E.19: Use a `final_action` object to express cleanup if no suitable resource handle is available](#Re-finally)
@@ -16090,11 +16095,11 @@ To rethrow a caught exception use `throw;` not `throw e;`. Using `throw e;` woul
1609016095
* Flag catching by value of a type that has a virtual function.
1609116096
* Flag throwing raw pointers.
1609216097

16093-
### <a name="Re-never-fail"></a>E.16: Destructors, deallocation, and `swap` must never fail
16098+
### <a name="Re-never-fail"></a>E.16: Destructors, deallocation, `swap`, and exception type copy/move construction must never fail
1609416099

1609516100
##### Reason
1609616101

16097-
We don't know how to write reliable programs if a destructor, a swap, or a memory deallocation fails; that is, if it exits by an exception or simply doesn't perform its required action.
16102+
We don't know how to write reliable programs if a destructor, a swap, a memory deallocation, or attempting to copy/move-construct an exception object fails; that is, if it exits by an exception or simply doesn't perform its required action.
1609816103

1609916104
##### Example, don't
1610016105

@@ -16123,14 +16128,17 @@ The standard library assumes that destructors, deallocation functions (e.g., `op
1612316128

1612416129
##### Note
1612516130

16126-
Deallocation functions, including `operator delete`, must be `noexcept`. `swap` functions must be `noexcept`.
16127-
Most destructors are implicitly `noexcept` by default.
16128-
Also, [make move operations `noexcept`](#Rc-move-noexcept).
16131+
* Deallocation functions, including `operator delete`, must be `noexcept`.
16132+
* `swap` functions must be `noexcept`.
16133+
* Most destructors are implicitly `noexcept` by default.
16134+
* Also, [make move operations `noexcept`](#Rc-move-noexcept).
16135+
* If writing a type intended to be used as an exception type, ensure its copy constructor is not `noexcept`. In general we cannot mechanically enforce this, because we do not know whether a type is intended to be used as an exception type.
16136+
* Try not to `throw` a type whose copy constructor is not `noexcept`. In general we cannot mechanically enforce this, because even `throw std::string(...)` could throw but does not in practice.
1612916137

1613016138
##### Enforcement
1613116139

16132-
Catch destructors, deallocation operations, and `swap`s that `throw`.
16133-
Catch such operations that are not `noexcept`.
16140+
* Catch destructors, deallocation operations, and `swap`s that `throw`.
16141+
* Catch such operations that are not `noexcept`.
1613416142

1613516143
**See also**: [discussion](#Sd-never-fail)
1613616144

@@ -16207,14 +16215,14 @@ Better:
1620716215

1620816216
##### Reason
1620916217

16210-
`finally` is less verbose and harder to get wrong than `try`/`catch`.
16218+
`finally` from the [GSL](#S-gsl) is less verbose and harder to get wrong than `try`/`catch`.
1621116219

1621216220
##### Example
1621316221

1621416222
void f(int n)
1621516223
{
1621616224
void* p = malloc(n);
16217-
auto _ = finally([p] { free(p); });
16225+
auto _ = gsl::finally([p] { free(p); });
1621816226
// ...
1621916227
}
1622016228

@@ -20302,6 +20310,14 @@ For writing to a file, there is rarely a need to `flush`.
2030220310

2030320311
##### Note
2030420312

20313+
For string streams (specifically `ostringstream`), the insertion of an `endl` is entirely equivalent
20314+
to the insertion of a `'\n'` character, but also in this case, `endl` might be significantly slower.
20315+
20316+
`endl` does *not* take care of producing a platform specific end-of-line sequence (like "\r\n" on
20317+
Windows). So for a string stream, `s << endl` just inserts a *single* character, `'\n'`.
20318+
20319+
##### Note
20320+
2030520321
Apart from the (occasionally important) issue of performance,
2030620322
the choice between `'\n'` and `endl` is almost completely aesthetic.
2030720323

@@ -21232,7 +21248,7 @@ Many of them are very similar to what became part of the ISO C++ standard in C++
2123221248
* `Unique_pointer` // A type that matches `Pointer`, is movable, and is not copyable
2123321249
* `Shared_pointer` // A type that matches `Pointer`, and is copyable
2123421250

21235-
# <a name="S-naming"></a>NL: Naming and layout rules
21251+
# <a name="S-naming"></a>NL: Naming and layout suggestions
2123621252

2123721253
Consistent naming and layout are helpful.
2123821254
If for no other reason because it minimizes "my style is better than your style" arguments.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Many of the guidelines make use of the header-only Guidelines Support Library. O
1818

1919
## Background and scope
2020

21-
The aim of the guidelines is to help people to use modern C++ effectively. By "modern C++" we mean C++11, C++14, and C++17. In other
21+
The aim of the guidelines is to help people to use modern C++ effectively. By "modern C++" we mean C++11 and newer. In other
2222
words, what would you like your code to look like in 5 years' time, given that you can start now? In 10 years' time?
2323

2424
The guidelines are focused on relatively higher-level issues, such as interfaces, resource management, memory management, and concurrency. Such

scripts/hunspell/isocpp.dic

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@ Lakos
286286
Lakos96
287287
Lavavej
288288
LCSD05
289+
legacy_class
289290
lifecycle
290291
*life-time
291292
linearization
@@ -301,6 +302,8 @@ lvalues
301302
m1
302303
m2
303304
m3
305+
m_owning;
306+
m_observer;
304307
macros2
305308
malloc
306309
mallocfree
@@ -389,6 +392,7 @@ optimizable
389392
O'Reilly
390393
org
391394
ostream
395+
ostringstream
392396
overabstract
393397
overconstrain
394398
overconstrained

0 commit comments

Comments
 (0)