You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* [C.4: Make a function a member only if it needs direct access to the representation of a class](#Rc-member)
3217
3217
* [C.5: Place helper functions in the same namespace as the class they support](#Rc-helper)
3218
3218
* [C.7: Don't define a class or enum and declare a variable of its type in the same statement](#Rc-standalone)
3219
+
* [C.8: use `class` rather that `struct` if any member is non-public](#Rc-class)
3220
+
* [C.9: minimize exposure of members](#Rc-private)
3219
3221
3220
3222
Subsections:
3221
3223
@@ -3254,11 +3256,18 @@ Probably impossible. Maybe a heuristic looking for data items used together is p
3254
3256
3255
3257
##### Reason
3256
3258
3257
-
Ease of comprehension. The use of `class` alerts the programmer to the need for an invariant.
3259
+
Readability.
3260
+
Ease of comprehension.
3261
+
The use of `class` alerts the programmer to the need for an invariant.
3262
+
This is a useful convention.
3258
3263
3259
3264
##### Note
3260
3265
3261
-
An invariant is a logical condition for the members of an object that a constructor must establish for the public member functions to assume. After the invariant is established (typically by a constructor) every member function can be called for the object. An invariant can be stated informally (e.g., in a comment) or more formally using `Expects`.
3266
+
An invariant is a logical condition for the members of an object that a constructor must establish for the public member functions to assume.
3267
+
After the invariant is established (typically by a constructor) every member function can be called for the object.
3268
+
An invariant can be stated informally (e.g., in a comment) or more formally using `Expects`.
3269
+
3270
+
If all data members can vary independently of each other, no invariant is possible.
3262
3271
3263
3272
##### Example
3264
3273
@@ -3270,14 +3279,25 @@ An invariant is a logical condition for the members of an object that a construc
3270
3279
but:
3271
3280
3272
3281
class Date {
3282
+
public:
3283
+
Date(int yy, Month mm, char dd); // validate that {yy, mm, dd} is a valid date and initialize
3284
+
// ...
3273
3285
private:
3274
3286
int y;
3275
3287
Month m;
3276
3288
char d; // day
3277
-
public:
3278
-
Date(int yy, Month mm, char dd); // validate that {yy, mm, dd} is a valid date and initialize
3279
-
// ...
3280
3289
};
3290
+
3291
+
##### Note
3292
+
3293
+
If a class has any `private` data, a user cannot completely initialize an object without the use of a constructor.
3294
+
Hence, the class definer will provide a constructor and must specify its meaning.
3295
+
This effectivily means the definer need to define an invariant.
3296
+
3297
+
* See also [define a class with private data as `class`](#Rc-class).
3298
+
* See also [Prefer to place the interface first in a class](#Rl-order).
3299
+
* See also [minimize exposure of members](#Rc-private).
3300
+
* See also [Avoid `protected` data](#Rh-protected).
3281
3301
3282
3302
##### Enforcement
3283
3303
@@ -3387,6 +3407,63 @@ Mixing a type definition and the definition of another entity in the same declar
3387
3407
* Flag if the `}` of a class or enumeration definition is not followed by a `;`. The `;` is missing.
3388
3408
3389
3409
3410
+
### <a name="Rc-class"></a>C.8: use `class` rather that `struct` if any member is non-public
3411
+
3412
+
##### Reason
3413
+
3414
+
Readability.
3415
+
To make it clear that something is being hidden/abstracted.
3416
+
This is a useful convention.
3417
+
3418
+
##### Example, bad
3419
+
3420
+
struct Date {
3421
+
int d,m;
3422
+
3423
+
Date(int i, Month m);
3424
+
// ... lots of functions ...
3425
+
private:
3426
+
int y; // year
3427
+
};
3428
+
3429
+
There is nothing wrong with this code as far as the C++ language rules are concerned,
3430
+
but nearly everything is wrong from a design perspective.
3431
+
The private data is hidden far from the public data.
3432
+
The data is split in different parts of the class declaration.
3433
+
Different parts of the data has difference access.
3434
+
All of this decreases readability and complicates maintenance.
3435
+
3436
+
3437
+
##### Note
3438
+
3439
+
Prefer to place the interface first in a class [see](#Rl-order).
3440
+
3441
+
##### Enforcement
3442
+
3443
+
Flag classes declarate with `struct` if there is a `private` or `public` member.
3444
+
3445
+
3446
+
### <a name="Rc-private"></a>C.9: minimize exposure of members
3447
+
3448
+
##### Reason
3449
+
3450
+
Encapsulation.
3451
+
Information hiding.
3452
+
Mimimize the chance of untended access.
3453
+
This simplifies maintenance.
3454
+
3455
+
##### Example
3456
+
3457
+
???
3458
+
3459
+
##### Note
3460
+
3461
+
Prefer the order `public` members before `protected` members before `private` members [see](#Rl-order).
@@ -5495,7 +5572,6 @@ Designing rules for classes in a hierarchy summary:
5495
5572
* [C.128: Use `override` to make overriding explicit in large class hierarchies](#Rh-override)
5496
5573
* [C.129: When designing a class hierarchy, distinguish between implementation inheritance and interface inheritance](#Rh-kind)
5497
5574
* [C.130: Redefine or prohibit copying for a base class; prefer a virtual `clone` function instead](#Rh-copy)
5498
-
5499
5575
* [C.131: Avoid trivial getters and setters](#Rh-get)
5500
5576
* [C.132: Don't make a function `virtual` without reason](#Rh-virtual)
5501
5577
* [C.133: Avoid `protected` data](#Rh-protected)
@@ -8102,9 +8178,10 @@ The *always initialize* rule is a style rule aimed to improve maintainability as
8102
8178
8103
8179
Here is an example that is often considered to demonstrate the need for a more relaxed rule for initialization
8104
8180
8105
-
widget i, j; // "widget" a type that's expensive to initialize, possibly a large POD
8181
+
widget i; // "widget" a type that's expensive to initialize, possibly a large POD
8182
+
widget j;
8106
8183
8107
-
if (cond) { // bad: i and j are initialized "late"
8184
+
if (cond) { // bad: i and j are initialized "late"
8108
8185
i = f1();
8109
8186
j = f2();
8110
8187
}
@@ -8939,7 +9016,7 @@ Readability.
8939
9016
8940
9017
##### Enforcement
8941
9018
8942
-
Flag empty statements that are not blocks and doesn't "contain" comments.
9019
+
Flag empty statements that are not blocks and don't "contain" comments.
8943
9020
8944
9021
8945
9022
### <a name="Res-loop-counter"></a>ES.86: Avoid modifying loop control variables inside the body of raw for-loops
@@ -9301,7 +9378,7 @@ Flag `const_cast`s.
9301
9378
9302
9379
##### Reason
9303
9380
9304
-
Constructs that cannot overflow, don't, and usually runs faster:
9381
+
Constructs that cannot overflow, don't, and usually run faster:
9305
9382
9306
9383
##### Example
9307
9384
@@ -9383,7 +9460,7 @@ also define an overload that takes lvalues.
9383
9460
void print(const string& s); // print and preserve the value of s
9384
9461
9385
9462
An rvalue can be assumed not to be accessed after being passed.
9386
-
An lvalue must in general be assumed to be used again after being passes, that is after a `std::move`,
9463
+
An lvalue must in general be assumed to be used again after being passed, that is after a `std::move`,
9387
9464
so "careful programming" is essential to avoid disasters -- better not rely on that.
9388
9465
9389
9466
###### Note
@@ -9861,7 +9938,7 @@ See also:
9861
9938
9862
9939
It is hard to be certain that concurrency isn't used now or sometime in the future.
9863
9940
Code gets re-used.
9864
-
Libraries using threads my be used from some other part of the program.
9941
+
Libraries using threads may be used from some other part of the program.
9865
9942
Note that this applies most urgently to library code and least urgently to stand-alone applications.
9866
9943
9867
9944
##### Example
@@ -9894,7 +9971,7 @@ There are several ways that this example could be made safe for a multi-threaded
9894
9971
However, there are also many examples where code that was "known" to never run in a multi-threaded program
9895
9972
was run as part of a multi-threaded program. Often years later.
9896
9973
Typically, such programs lead to a painful effort to remove data races.
9897
-
Therefore, code that is never intended to run in a multi-threaded environment should be clearly labeled as such.
9974
+
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.
9898
9975
9899
9976
### <a name="Rconc-races"></a>CP.2: Avoid data races
9900
9977
@@ -9980,7 +10057,7 @@ Error handling involves:
9980
10057
* Preserve the state of a program in a valid state
9981
10058
* Avoid resource leaks
9982
10059
9983
-
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.
10060
+
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.
9984
10061
9985
10062
The rules are designed to help avoid several kinds of errors:
9986
10063
@@ -10106,7 +10183,7 @@ There is nothing exceptional about finding a value in a `vector`.
10106
10183
10107
10184
##### Reason
10108
10185
10109
-
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.
10186
+
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.
10110
10187
10111
10188
##### Note
10112
10189
@@ -10117,7 +10194,7 @@ An [invariant](#Rc-struct) is logical condition for the members of an object tha
10117
10194
##### Reason
10118
10195
10119
10196
Leaving an object without its invariant established is asking for trouble.
10120
-
Not all member function can be called.
10197
+
Not all member functions can be called.
10121
10198
10122
10199
##### Example
10123
10200
@@ -10162,7 +10239,7 @@ This is verbose. In larger code with multiple possible `throw`s explicit release
10162
10239
10163
10240
void f3(int i) // OK: resource management done by a handle
10164
10241
{
10165
-
auto p = make_unique<int[12]>();
10242
+
auto p = make_unique<int[]>(12);
10166
10243
// ...
10167
10244
if (i < 17) throw Bad {"in f()", i};
10168
10245
// ...
@@ -10172,7 +10249,7 @@ Note that this works even when the `throw` is implicit because it happened in a
10172
10249
10173
10250
void f4(int i) // OK: resource management done by a handle
10174
10251
{
10175
-
auto p = make_unique<int[12]>();
10252
+
auto p = make_unique<int[]>(12);
10176
10253
// ...
10177
10254
helper(i); // may throw
10178
10255
// ...
@@ -10199,12 +10276,12 @@ First challenge that assumption; there are many anti-exceptions myths around.
10199
10276
We know of only a few good reasons:
10200
10277
10201
10278
* We are on a system so small that the exception support would eat up most of our 2K or memory.
10202
-
* 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.
10279
+
* 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.
10203
10280
* We are in a system with tons of legacy code using lots of pointers in difficult-to-understand ways
10204
10281
(in particular without a recognizable ownership strategy) so that exceptions could cause leaks.
10205
10282
* We get fired if we challenge our manager's ancient wisdom.
10206
10283
10207
-
Only the first of these reasons is fundamental, so whenever possible, use exception to implement RAII.
10284
+
Only the first of these reasons is fundamental, so whenever possible, use exceptions to implement RAII, or design your RAII objects to never fail.
10208
10285
When exceptions cannot be used, simulate RAII.
10209
10286
That is, systematically check that objects are valid after construction and still release all resources in the destructor.
10210
10287
One strategy is to add a `valid()` operation to every resource handle:
@@ -10276,7 +10353,7 @@ Many standard library functions are `noexcept` including all the standard librar
10276
10353
// ... do something ...
10277
10354
}
10278
10355
10279
-
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.
10356
+
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.
10280
10357
10281
10358
**See also**: [discussion](#Sd-noexcept).
10282
10359
@@ -10409,7 +10486,7 @@ Instead, use:
10409
10486
10410
10487
##### Enforcement
10411
10488
10412
-
Flag by-value exceptions if their type are part of a hierarchy (could require whole-program analysis to be perfect).
10489
+
Flag by-value exceptions if their types are part of a hierarchy (could require whole-program analysis to be perfect).
10413
10490
10414
10491
### <a name="Re-never-fail"></a>E.16: Destructors, deallocation, and `swap` must never fail
10415
10492
@@ -10431,15 +10508,15 @@ We don't know how to write reliable programs if a destructor, a swap, or a memor
10431
10508
10432
10509
##### Note
10433
10510
10434
-
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.
10511
+
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.
10435
10512
10436
10513
##### Note
10437
10514
10438
10515
The standard library assumes that destructors, deallocation functions (e.g., `operator delete`), and `swap` do not throw. If they do, basic standard library invariants are broken.
10439
10516
10440
10517
##### Note
10441
10518
10442
-
Deallocation functions, including `operator delete`, must be `noexcept`. `swap` functions must be `noexcept`. Most destructors are implicitly `noexcept` by default. destructors, make them `noexcept`.
10519
+
Deallocation functions, including `operator delete`, must be `noexcept`. `swap` functions must be `noexcept`. Most destructors are implicitly `noexcept` by default.
10443
10520
10444
10521
##### Enforcement
10445
10522
@@ -10513,7 +10590,7 @@ Let cleanup actions on the unwinding path be handled by [RAII](#Re-raii).
10513
10590
# <a name="S-const"></a>Con: Constants and Immutability
10514
10591
10515
10592
You can't have a race condition on a constant.
10516
-
it is easier to reason about a program when many of the objects cannot change their values.
10593
+
It is easier to reason about a program when many of the objects cannot change their values.
10517
10594
Interfaces that promises "no change" of objects passed as arguments greatly increase readability.
10518
10595
10519
10596
Constant rule summary:
@@ -10607,6 +10684,10 @@ This gives a more precise statement of design intent, better readability, more e
10607
10684
10608
10685
???
10609
10686
10687
+
##### Note
10688
+
10689
+
See F.4.
10690
+
10610
10691
##### Enforcement
10611
10692
10612
10693
???
@@ -10994,7 +11075,7 @@ It is better and simpler just to use `Sortable`:
10994
11075
10995
11076
##### Note
10996
11077
10997
-
The set of "standard" concepts is evolving as we approaches real (ISO) standardization.
11078
+
The set of "standard" concepts is evolving as we approach real (ISO) standardization.
10998
11079
10999
11080
##### Note
11000
11081
@@ -11145,7 +11226,7 @@ Examples of complete sets are
11145
11226
##### Reason
11146
11227
11147
11228
A meaningful/useful concept has a semantic meaning.
11148
-
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.
11229
+
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.
11149
11230
Specifying semantics is a powerful design tool.
11150
11231
11151
11232
##### Example
@@ -11310,7 +11391,7 @@ Conversions are taken into account. You don't have to remember the names of all
11310
11391
##### Reason
11311
11392
11312
11393
Function objects can carry more information through an interface than a "plain" pointer to function.
11313
-
In general, passing function objects give better performance than passing pointers to functions.
11394
+
In general, passing function objects gives better performance than passing pointers to functions.
11314
11395
11315
11396
##### Example
11316
11397
@@ -11381,7 +11462,7 @@ This saves the user of `Matrix` from having to know that its elements are stored
11381
11462
##### Example
11382
11463
11383
11464
template<typename T>
11384
-
using Value_type<T> = container_traits<T>::value_type;
11465
+
using Value_type = typename container_traits<T>::value_type;
11385
11466
11386
11467
This saves the user of `Value_type` from having to know the technique used to implement `value_type`s.
11387
11468
@@ -11742,7 +11823,7 @@ There are three major ways to let calling code customize a template.
11742
11823
11743
11824
Templates are the backbone of C++'s support for generic programming and class hierarchies the backbone of its support
11744
11825
for object-oriented programming.
11745
-
The two language mechanisms can be use effectively in combination, but a few design pitfalls must be avoided.
11826
+
The two language mechanisms can be used effectively in combination, but a few design pitfalls must be avoided.
11746
11827
11747
11828
### <a name="Rt-hier"></a>T.80: Do not naively templatize a class hierarchy
11748
11829
@@ -12162,7 +12243,8 @@ That makes the code concise and gives better locality than alternatives.
12162
12243
12163
12244
##### Example
12164
12245
12165
-
??? for-loop equivalent
12246
+
auto earlyUsersEnd = std::remove_if(users.begin(), users.end(),
12247
+
[](const User &a) { return a.id > 100; });
12166
12248
12167
12249
**Exception**: Naming a lambda can be useful for clarity even if it is used only once
12168
12250
@@ -13886,10 +13968,17 @@ Use the `public` before `protected` before `private` order.
13886
13968
13887
13969
Private types and functions can be placed with private data.
13888
13970
13971
+
Avoid multiple blocks of declarations of one access (e.g., `public`) dispersed among blocks of declarations with different access (e.g. `private`).
13972
+
13889
13973
##### Example
13890
13974
13891
13975
???
13892
13976
13977
+
##### Note
13978
+
13979
+
The use of macros to declare groups of members often violates any ordering rules.
13980
+
However, macros obscures what is being expressed anyway.
13981
+
13893
13982
##### Enforcement
13894
13983
13895
13984
Flag departures from the suggested order. There will be a lot of old code that doesn't follow this rule.
0 commit comments