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
* [E.18: Minimize the use of explicit `try`/`catch`](#Re-catch)
12042
12042
* [E.19: Use a `final_action` object to express cleanup if no suitable resource handle is available](#Re-finally)
12043
12043
12044
-
* [E.25: If you can't throw exceptions, simulate RAII for resource management](Re-no-throw-raii)
12044
+
* [E.25: If you can't throw exceptions, simulate RAII for resource management](#Re-no-throw-raii)
12045
12045
* [E.26: If you can't throw exceptions, consider failing fast](#Re-no-throw-crash)
12046
12046
* [E.27: If you can't throw exceptions, use error codes systematically](#Re-no-throw-codes)
12047
12047
* [E.28: Avoid error handling based on global state (e.g. `errno`)](#Re-no-throw)
@@ -12113,7 +12113,9 @@ Don't use a `throw` as simply an alternative way of returning a value from a fun
12113
12113
12114
12114
##### Note
12115
12115
12116
-
Before deciding that you cannot afford or don't like exception-based error handling, have a look at the [alternatives](#Re-no-throw-raii).
12116
+
Before deciding that you cannot afford or don't like exception-based error handling, have a look at the [alternatives](#Re-no-throw-raii);
12117
+
they have their own complexities and problems.
12118
+
Also, as far as possible, measure before making claims about efficiency.
12117
12119
12118
12120
### <a name="Re-errors"></a>E.3: Use exceptions for error handling only
12119
12121
@@ -12139,6 +12141,11 @@ C++ implementations tend to be optimized based on the assumption that exceptions
12139
12141
This is more complicated and most likely runs much slower than the obvious alternative.
12140
12142
There is nothing exceptional about finding a value in a `vector`.
12141
12143
12144
+
##### Enforcement
12145
+
12146
+
Would need to be heuristic.
12147
+
Look for exception values "leaked" out of `catch` clauses.
12148
+
12142
12149
### <a name="Re-design-invariants"></a>E.4: Design your error-handling strategy around invariants
12143
12150
12144
12151
##### Reason
@@ -12149,6 +12156,10 @@ To use an object it must be in a valid state (defined formally or informally by
12149
12156
12150
12157
An [invariant](#Rc-struct) is logical condition for the members of an object that a constructor must establish for the public member functions to assume.
12151
12158
12159
+
##### Enforcement
12160
+
12161
+
???
12162
+
12152
12163
### <a name="Re-invariant"></a>E.5: Let a constructor establish an invariant, and throw if it cannot
12153
12164
12154
12165
##### Reason
@@ -12158,13 +12169,29 @@ Not all member functions can be called.
12158
12169
12159
12170
##### Example
12160
12171
12161
-
???
12172
+
class vector { // very simplified vector of doubles
12173
+
// if elem!=nullptr then elem points to sz doubles
The class invariant - here stated as a comment - is established by the constructors.
12187
+
`new` throws if it cannot allocate the required memory.
12188
+
The operators, notably the subscript operator, relies on the invariant.
12162
12189
12163
12190
**See also**: [If a constructor cannot construct a valid object, throw an exception](#Rc-throw)
12164
12191
12165
12192
##### Enforcement
12166
12193
12167
-
???
12194
+
Flag classes with `private` state witout a constructor (public, protected, or private).
12168
12195
12169
12196
### <a name="Re-raii"></a>E.6: Use RAII to prevent leaks
12170
12197
@@ -12239,6 +12266,9 @@ We know of only a few good reasons:
12239
12266
* 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.
12240
12267
* We are in a system with tons of legacy code using lots of pointers in difficult-to-understand ways
12241
12268
(in particular without a recognizable ownership strategy) so that exceptions could cause leaks.
12269
+
* Our implemention of the C++ exeption mechanisms is unreasonably poor
12270
+
(slow, memory consuming, failing to work correctly for dynamically linked libraries, etc.).
12271
+
Complain to your implementation purveyer; if no user complains, no improvement will happen.
12242
12272
* We get fired if we challenge our manager's ancient wisdom.
12243
12273
12244
12274
Only the first of these reasons is fundamental, so whenever possible, use exceptions to implement RAII, or design your RAII objects to never fail.
@@ -12264,7 +12294,7 @@ One strategy is to add a `valid()` operation to every resource handle:
12264
12294
Obviously, this increases the size of the code, doesn't allow for implicit propagation of "exceptions" (`valid()` checks), and `valid()` checks can be forgotten.
12265
12295
Prefer to use exceptions.
12266
12296
12267
-
**See also**: [discussion](#Sd-noexcept).
12297
+
**See also**: [Use of `noexcept`](#Se-noexcept).
12268
12298
12269
12299
##### Enforcement
12270
12300
@@ -12299,7 +12329,8 @@ To make error handling systematic, robust, and efficient.
12299
12329
return log(sqrt(d <= 0 ? 1 : d));
12300
12330
}
12301
12331
12302
-
Here, I know that `compute` will not throw because it is composed out of operations that don't throw. By declaring `compute` to be `noexcept` I give the compiler and human readers information that can make it easier for them to understand and manipulate `compute`.
12332
+
Here, we know that `compute` will not throw because it is composed out of operations that don't throw.
12333
+
By declaring `compute` to be `noexcept`, we give the compiler and human readers information that can make it easier for them to understand and manipulate `compute`.
12303
12334
12304
12335
##### Note
12305
12336
@@ -12343,6 +12374,14 @@ One way of avoiding such problems is to use resource handles consistently:
12343
12374
// no need for delete p
12344
12375
}
12345
12376
12377
+
Another solution (often better) would be to use a local variable to eliminate explicit use of pointers:
12378
+
12379
+
void no_leak(_simplified(int x)
12380
+
{
12381
+
vector<int> v(7);
12382
+
// ...
12383
+
}
12384
+
12346
12385
**See also**: ???resource rule ???
12347
12386
12348
12387
### <a name="Re-exception-types"></a>E.14: Use purpose-designed user-defined types as exceptions (not built-in types)
@@ -12468,19 +12507,27 @@ We don't know how to write reliable programs if a destructor, a swap, or a memor
12468
12507
12469
12508
##### Note
12470
12509
12471
-
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.
12510
+
Many have tried to write reliable code violating this rule for examples, such as a network connection that "refuses to close".
12511
+
To the best of our knowledge nobody has found a general way of doing this.
12512
+
Occasionally, for very specific examples, you can get away with setting some state for future cleanup.
12513
+
For example, we might put a socket that does not want to close on a "bad socket" list,
12514
+
to be examined by a regular sweep of the system state.
12515
+
Every example we have seen of this is error-prone, specialized, and often buggy.
12472
12516
12473
12517
##### Note
12474
12518
12475
12519
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.
12476
12520
12477
12521
##### Note
12478
12522
12479
-
Deallocation functions, including `operator delete`, must be `noexcept`. `swap` functions must be `noexcept`. Most destructors are implicitly `noexcept` by default.
12523
+
Deallocation functions, including `operator delete`, must be `noexcept`. `swap` functions must be `noexcept`.
12524
+
Most destructors are implicitly `noexcept` by default.
0 commit comments