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
@@ -5712,7 +5712,7 @@ Interfaces should normally be composed entirely of public pure virtual functions
5712
5712
5713
5713
The `Derived` is `delete`d through its `Goof` interface, so its `string` is leaked.
5714
5714
Give `Goof` a virtual destructor and all is well.
5715
-
5715
+
5716
5716
5717
5717
##### Enforcement
5718
5718
@@ -5733,14 +5733,14 @@ Such as on an ABI (link) boundary.
5733
5733
5734
5734
class D1 : public Device {
5735
5735
// ... data ...
5736
-
5736
+
5737
5737
void write(span<const char> outbuf) override;
5738
5738
void read(span<char> inbuf) override;
5739
5739
};
5740
5740
5741
5741
class D2 : public Device {
5742
5742
// ... differnt data ...
5743
-
5743
+
5744
5744
void write(span<const char> outbuf) override;
5745
5745
void read(span<char> inbuf) override;
5746
5746
};
@@ -5831,7 +5831,7 @@ Use `virtual` only when declaring a new virtual function. Use `override` only wh
5831
5831
};
5832
5832
5833
5833
struct D2 : B {
5834
-
virtual void f2(int) final; // BAD; pitfall, D2::f does not override B::f
5834
+
virtual void f2(int) final; // BAD; pitfall, D2::f does not override B::f
5835
5835
};
5836
5836
5837
5837
##### Enforcement
@@ -6130,7 +6130,7 @@ However, misuses are (or at least has been) far more common.
6130
6130
##### Enforcement
6131
6131
6132
6132
Flag uses of `final`.
6133
-
6133
+
6134
6134
6135
6135
## <a name="Rh-virtual-default-arg"></a>C.140: Do not provide different default arguments for a virtual function and an overrider
6136
6136
@@ -6645,7 +6645,7 @@ Many parts of the C++ semantics assumes its default meaning.
6645
6645
private:
6646
6646
T* p;
6647
6647
};
6648
-
6648
+
6649
6649
class X {
6650
6650
Ptr operator&() { return Ptr{this}; }
6651
6651
// ...
@@ -6753,7 +6753,7 @@ By itself, `cout_my_class` would be OK, but it is not usable/composabe with code
6753
6753
6754
6754
##### Note
6755
6755
6756
-
There are strong and vigorous conventions for the meaning most operators, such as
6756
+
There are strong and vigorous conventions for the meaning most operators, such as
6757
6757
6758
6758
* comparisons (`==`, `!=`, `<`, `<=`, `>`, and `>=`),
6759
6759
* arithmetic operations (`+`, `-`, `*`, `/`, and `%`)
@@ -9532,7 +9532,7 @@ double or int64 from int32), brace initialization may be used instead.
9532
9532
This makes it clear that the type conversion was intended and also prevents
9533
9533
conversions between types that might result in loss of precision. (It is a
9534
9534
compilation error to try to initialize a float from a double in this fashion,
9535
-
for example.)
9535
+
for example.)
9536
9536
9537
9537
##### Enforcement
9538
9538
@@ -9589,7 +9589,7 @@ Moving is done implicitly when the source is an rvalue (e.g., value in a `return
9589
9589
9590
9590
In general, following the guidelines in this document (including not making variables' scopes needlessly large, writing short functions that return values, returning local variables) help eliminate most need for explicit `std::move`.
9591
9591
9592
-
Explicit `move` is needed to explicitly move an object to another scope, notably to pass it to a "sink" function and in the implementations of the move operations themselves (move constructor, move assignment operator) and swap operations.
9592
+
Explicit `move` is needed to explicitly move an object to another scope, notably to pass it to a "sink" function and in the implementations of the move operations themselves (move constructor, move assignment operator) and swap operations.
9593
9593
9594
9594
##### Example, bad
9595
9595
@@ -9612,7 +9612,7 @@ And after you do that, assume the object has been moved from (see [C.64](#Rc-mov
9612
9612
9613
9613
string s2 = s1; // ok, takes a copy
9614
9614
assert(s1=="supercalifragilisticexpialidocious"); // ok
9615
-
9615
+
9616
9616
string s3 = move(s1); // bad, if you want to keep using s1's value
9617
9617
assert(s1=="supercalifragilisticexpialidocious"); // bad, assert will likely fail, s1 likely changed
9618
9618
}
@@ -9624,9 +9624,9 @@ And after you do that, assume the object has been moved from (see [C.64](#Rc-mov
9624
9624
void f() {
9625
9625
auto w = make_unique<widget>();
9626
9626
// ...
9627
-
sink( std::move(w) ); // ok, give to sink()
9627
+
sink( std::move(w) ); // ok, give to sink()
9628
9628
// ...
9629
-
sink(w); // Error: unique_ptr is carefully designed so that you cannot copy it
9629
+
sink(w); // Error: unique_ptr is carefully designed so that you cannot copy it
9630
9630
}
9631
9631
9632
9632
##### Notes
@@ -9648,7 +9648,7 @@ In general, don't complicate your code without reason (??)
9648
9648
9649
9649
Never write `return move(local_variable);`, because the language already knows the variable is a move candidate.
9650
9650
Writing `move` in this code won't help, and can actually be detrimental because on some compilers it interferes with RVO (the return value optimization) by creating an additional reference alias to the local variable.
9651
-
9651
+
9652
9652
9653
9653
##### Example, bad
9654
9654
@@ -9676,7 +9676,7 @@ The language already knows that a returned value is a temporary object that can
9676
9676
9677
9677
* Flag use of `std::move(x)` where `x` is an rvalue or the language will already treat it as an rvalue, including `return std::move(local_variable);` and `std::move(f())` on a function that returns by value.
9678
9678
* Flag functions taking an `S&&` parameter if there is no `const S&` overload to take care of lvalues.
9679
-
* Flag a `std::move`s argument passed to a parameter, except when the parameter type is one of the following: an `X&&` rvalue reference; a `T&&` forwarding reference where `T` is a template parameter type; or by value and the type is move-only.
9679
+
* Flag a `std::move`s argument passed to a parameter, except when the parameter type is one of the following: an `X&&` rvalue reference; a `T&&` forwarding reference where `T` is a template parameter type; or by value and the type is move-only.
9680
9680
* Flag when `std::move` is applied to a forwarding reference (`T&&` where `T` is a template parameter type). Use `std::forward` instead.
9681
9681
* Flag when `std::move` is applied to other than an rvalue reference. (More general case of the previous rule to cover the non-forwarding cases.)
9682
9682
* Flag when `std::forward` is applied to an rvalue reference (`X&&` where `X` is a concrete type). Use `std::move` instead.
@@ -10927,7 +10927,7 @@ This, of course, assumes a good implementation of the exception handling mechani
10927
10927
There are also cases where the problems above do not apply, but exceptions cannot be used for other reasons.
10928
10928
Some hard real-time systems are an example: An operation has to be completed within a fixed time with an error or a correct answer.
10929
10929
In the absence of appropriate time estimation tools, this is hard to guarantee for exceptions.
10930
-
Such systems (e.g. flight control software) typically also ban the use of dynamic (heap) memory.
10930
+
Such systems (e.g. flight control software) typically also ban the use of dynamic (heap) memory.
10931
10931
10932
10932
So, the primary guideline for error handling is "use exceptions and [RAII](#Re-raii)."
10933
10933
This section deals with the cases where you either do not have an efficient implementation or exceptions
@@ -11065,7 +11065,7 @@ For example:
11065
11065
if (!r.second) {
11066
11066
// error handling
11067
11067
}
11068
-
Gadget& g = r.first;
11068
+
Gadget& g = r.first;
11069
11069
// ...
11070
11070
}
11071
11071
@@ -11084,7 +11084,7 @@ For example:
11084
11084
if (!r.err) {
11085
11085
// error handling
11086
11086
}
11087
-
Gadget& g = r.val;
11087
+
Gadget& g = r.val;
11088
11088
// ...
11089
11089
}
11090
11090
@@ -11102,21 +11102,21 @@ This can be messy:
11102
11102
if (!g1.valid()) {
11103
11103
return {0,g1_error};
11104
11104
}
11105
-
11105
+
11106
11106
Gadget g2 = make_gadget(17);
11107
11107
if (!g2.valid()) {
11108
11108
cleanup(g1);
11109
11109
return {0,g2_error};
11110
11110
}
11111
-
11111
+
11112
11112
// ...
11113
-
11113
+
11114
11114
if (all_foobar(g1,g2)) {
11115
11115
cleanup(g1);
11116
11116
cleanup(g2);
11117
11117
return {0,foobar_error};
11118
11118
// ...
11119
-
11119
+
11120
11120
cleanup(g1);
11121
11121
cleanup(g2);
11122
11122
return {res,0};
@@ -11128,26 +11128,26 @@ A not uncommon technique is to gather cleanup at the end of the function to avoi
11128
11128
std::pair<int,error_indicator> user()
11129
11129
{
11130
11130
error_indicator err = 0;
11131
-
11131
+
11132
11132
Gadget g1 = make_gadget(17);
11133
11133
if (!g1.valid()) {
11134
11134
err = g2_error;
11135
11135
goto exit;
11136
11136
}
11137
-
11137
+
11138
11138
Gadget g2 = make_gadget(17);
11139
11139
if (!g2.valid()) {
11140
11140
err = g2_error;
11141
11141
goto exit;
11142
11142
}
11143
-
11143
+
11144
11144
if (all_foobar(g1,g2)) {
11145
11145
err = foobar_error;
11146
11146
goto exit;
11147
11147
}
11148
11148
// ...
11149
11149
11150
-
exit:
11150
+
exit:
11151
11151
if (g1.valid()) cleanup(g1);
11152
11152
if (g1.valid()) cleanup(g2);
11153
11153
return {res,err};
@@ -11294,7 +11294,7 @@ but that should be done only when the called function is supposed to modify the
11294
11294
{
11295
11295
int x = 7;
11296
11296
const int y = 9;
11297
-
11297
+
11298
11298
for (;;) {
11299
11299
// ...
11300
11300
}
@@ -12087,10 +12087,10 @@ The rule supports the view that a concept should reflect a (mathematically) cohe
12087
12087
{
12088
12088
if (!(x==y) { /* ... */ } // OK
12089
12089
if (x!=y) { /* ... */ } //surprise! error
12090
-
12090
+
12091
12091
while (!(x<y)) { /* ... */ } // OK
12092
12092
while (x>=y) { /* ... */ } //surprise! error
12093
-
12093
+
12094
12094
x = x+y; // OK
12095
12095
x += y; // surprise! error
12096
12096
}
@@ -12114,10 +12114,10 @@ It could even be less efficient.
12114
12114
{
12115
12115
if (!(x==y) { /* ... */ } // OK
12116
12116
if (x!=y) { /* ... */ } //OK
12117
-
12117
+
12118
12118
while (!(x<y)) { /* ... */ } // OK
12119
12119
while (x>=y) { /* ... */ } //OK
12120
-
12120
+
12121
12121
x = x+y; // OK
12122
12122
x += y; // OK
12123
12123
}
@@ -13533,7 +13533,7 @@ For a variable-length array, use `std::vector`, which additionally can change it
13533
13533
##### Example
13534
13534
13535
13535
int v[SIZE]; // BAD
13536
-
13536
+
13537
13537
std::array<int,SIZE> w; // ok
13538
13538
13539
13539
##### Example
@@ -13557,15 +13557,15 @@ Even when other containers seem more suited, such a `map` for O(log N) lookup pe
13557
13557
13558
13558
##### Note
13559
13559
13560
-
`string` should not be used as a container of individual characters. A `string` is a textual string; if you want a container of characters, use `vector</*char_type*/>` or `array</*char_type*/>` instead.
13560
+
`string` should not be used as a container of individual characters. A `string` is a textual string; if you want a container of characters, use `vector</*char_type*/>` or `array</*char_type*/>` instead.
13561
13561
13562
13562
##### Exceptions
13563
13563
13564
13564
If you have a good reason to use another container, use that instead. For example:
13565
13565
13566
13566
* If `vector` suits your needs but you don't need the container to be variable size, use `array` instead.
13567
13567
13568
-
* If you want a dictionary-style lookup container that guarantees O(K) or O(log N) lookups, the container will be larger (more than a few KB) and you perform frequent inserts so that the overhead of maintaining a sorted `vector` is infeasible, go ahead and use an `unordered_map` or `map` instead.
13568
+
* If you want a dictionary-style lookup container that guarantees O(K) or O(log N) lookups, the container will be larger (more than a few KB) and you perform frequent inserts so that the overhead of maintaining a sorted `vector` is infeasible, go ahead and use an `unordered_map` or `map` instead.
13569
13569
13570
13570
##### Enforcement
13571
13571
@@ -13905,17 +13905,17 @@ Sometimes you may be tempted to resort to `const_cast` to avoid code duplication
13905
13905
class foo {
13906
13906
bar mybar;
13907
13907
public: // BAD, duplicates logic
13908
-
bar& get_bar() { /* complex logic around getting a non-const reference to mybar */ }
13909
-
const bar& get_bar() const { /* same complex logic around getting a const reference to mybar */ }
13908
+
bar& get_bar() { /* complex logic around getting a non-const reference to mybar */ }
13909
+
const bar& get_bar() const { /* same complex logic around getting a const reference to mybar */ }
13910
13910
};
13911
13911
13912
13912
Instead, prefer to share implementations. Normally, you can just have the non-`const` function call the `const` function. However, when there is complex logic this can lead to the following pattern that still resorts to a `const_cast`:
13913
13913
13914
13914
class foo {
13915
13915
bar mybar;
13916
13916
public: // not great, non-const calls const version but resorts to const_cast
const bar& get_bar() const { /* the complex logic around getting a const reference to mybar */ }
13919
13919
};
13920
13920
13921
13921
Although this pattern is safe when applied correctly, because the caller must have had a non-`const` object to begin with, it's not ideal because the safety is hard to enforce automatically as a checker rule.
@@ -13927,11 +13927,11 @@ Instead, prefer to put the common code in a common helper function -- and make i
13927
13927
13928
13928
template<class T> // good, deduces whether T is const or non-const
13929
13929
static auto get_bar_impl(T& t) -> decltype(t.get_bar())
13930
-
{ /* the complex logic around getting a possibly-const reference to mybar */ }
13930
+
{ /* the complex logic around getting a possibly-const reference to mybar */ }
**Exception**: You may need to cast away `const` when calling `const`-incorrect functions. Prefer to wrap such functions in inline `const`-correct wrappers to encapsulate the cast in one place.
@@ -15072,7 +15072,7 @@ Here is an example of the last option:
15072
15072
15073
15073
template<class T>
15074
15074
friend shared_ptr<T> B::Create();
15075
-
};
15075
+
};
15076
15076
15077
15077
shared_ptr<D> p = D::Create<D>(); // creating a D object
0 commit comments