mirror of
https://github.com/isocpp/CppCoreGuidelines.git
synced 2025-12-18 13:14:40 +03:00
a few more fix-ups in ES.*
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
# <a name="main"></a>C++ Core Guidelines
|
# <a name="main"></a>C++ Core Guidelines
|
||||||
|
|
||||||
April 4, 2017
|
April 9, 2017
|
||||||
|
|
||||||
|
|
||||||
Editors:
|
Editors:
|
||||||
@@ -9770,19 +9770,16 @@ For containers, there is a tradition for using `{...}` for a list of elements an
|
|||||||
|
|
||||||
##### Note
|
##### Note
|
||||||
|
|
||||||
Initialization of a variable declared using `auto` with a single value, e.g., `{v}`, had surprising results until recently:
|
Initialization of a variable declared using `auto` with a single value, e.g., `{v}`, had surprising results until C++17.
|
||||||
|
The C++17 rules are somewhat less surprising:
|
||||||
|
|
||||||
auto x1 {7}; // x1 is an int with the value 7
|
auto x1 {7}; // x1 is an int with the value 7
|
||||||
// x2 is an initializer_list<int> with an element 7
|
auto x2 = {7}; // x2 is an initializer_list<int> with an element 7
|
||||||
// (this will will change to "element 7" in C++17)
|
|
||||||
auto x2 = {7};
|
|
||||||
|
|
||||||
auto x11 {7, 8}; // error: two initializers
|
auto x11 {7, 8}; // error: two initializers
|
||||||
auto x22 = {7, 8}; // x2 is an initializer_list<int> with elements 7 and 8
|
auto x22 = {7, 8}; // x2 is an initializer_list<int> with elements 7 and 8
|
||||||
|
|
||||||
##### Exception
|
So use `={...}` if you really want an `initializer_list<T>`
|
||||||
|
|
||||||
Use `={...}` if you really want an `initializer_list<T>`
|
|
||||||
|
|
||||||
auto fib10 = {0, 1, 2, 3, 5, 8, 13, 21, 34, 55}; // fib10 is a list
|
auto fib10 = {0, 1, 2, 3, 5, 8, 13, 21, 34, 55}; // fib10 is a list
|
||||||
|
|
||||||
@@ -9826,12 +9823,16 @@ increases readability, and it has zero or near zero runtime cost.
|
|||||||
{
|
{
|
||||||
auto p1 = make_unique<int>(7); // OK
|
auto p1 = make_unique<int>(7); // OK
|
||||||
int* p2 = new int{7}; // bad: might leak
|
int* p2 = new int{7}; // bad: might leak
|
||||||
// ...
|
// ... no assignment to p2 ...
|
||||||
if (leak) return;
|
if (leak) return;
|
||||||
|
// ... no assignment to p2 ...
|
||||||
|
vector<int> v(7);
|
||||||
|
v.at(7) = 0; // exception thrown
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
|
|
||||||
If `leak == true` the object pointed to by `p2` is leaked and the object pointed to by `p1` is not.
|
If `leak == true` the object pointed to by `p2` is leaked and the object pointed to by `p1` is not.
|
||||||
|
The same is the case when `at()` throws.
|
||||||
|
|
||||||
##### Enforcement
|
##### Enforcement
|
||||||
|
|
||||||
@@ -10373,6 +10374,7 @@ consider `gsl::finally()` as a cleaner and more reliable alternative to `goto ex
|
|||||||
##### Reason
|
##### Reason
|
||||||
|
|
||||||
In a non-trivial loop body, it is easy to overlook a `break` or a `continue`.
|
In a non-trivial loop body, it is easy to overlook a `break` or a `continue`.
|
||||||
|
|
||||||
A `break` in a loop has a dramatically different meaning than a `break` in a `switch`-statement
|
A `break` in a loop has a dramatically different meaning than a `break` in a `switch`-statement
|
||||||
(and you can have `switch`-statement in a loop and a loop in a `switch`-case).
|
(and you can have `switch`-statement in a loop and a loop in a `switch`-case).
|
||||||
|
|
||||||
@@ -10861,11 +10863,29 @@ Flag uses of `0` and `NULL` for pointers. The transformation may be helped by si
|
|||||||
|
|
||||||
##### Reason
|
##### Reason
|
||||||
|
|
||||||
Casts are a well-known source of errors. Makes some optimizations unreliable.
|
Casts are a well-known source of errors. Make some optimizations unreliable.
|
||||||
|
|
||||||
##### Example
|
##### Example, bad
|
||||||
|
|
||||||
???
|
double d = 2;
|
||||||
|
auto p = (long*)&d;
|
||||||
|
auto q = (long long*)&d;
|
||||||
|
cout << d << ' ' << *p << ' ' << *q << '\n';
|
||||||
|
|
||||||
|
What would you think this fragment prints? The result is at best implementation defined. I got
|
||||||
|
|
||||||
|
2 0 4611686018427387904
|
||||||
|
|
||||||
|
Adding
|
||||||
|
|
||||||
|
*q = 666;
|
||||||
|
cout << d << ' ' << *p << ' ' << *q << '\n';
|
||||||
|
|
||||||
|
I got
|
||||||
|
|
||||||
|
3.29048e-321 666 666
|
||||||
|
|
||||||
|
Surprised? I'm just glad I didn't crash the program.
|
||||||
|
|
||||||
##### Note
|
##### Note
|
||||||
|
|
||||||
@@ -10910,15 +10930,29 @@ The named casts are:
|
|||||||
|
|
||||||
##### Example
|
##### Example
|
||||||
|
|
||||||
???
|
class B { /* ... */ };
|
||||||
|
class D { /* ... */ };
|
||||||
|
|
||||||
|
template<typename D> D* upcast(B* pb)
|
||||||
|
{
|
||||||
|
D* pd0 = pb; // error: no implicit conversion from B* to D*
|
||||||
|
D* pd1 = (D*)pb; // legal, but what is done?
|
||||||
|
D* pd2 = static_cast<D*>(pb); // error: D is not derived from B
|
||||||
|
D* pd3 = reinterpret_cast<D*>(pb); // OK: on your head be it!
|
||||||
|
D* pd4 = dynamic_cast<D*>(pb); // OK: return nullptr
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
The example was synthesized from real-world bugs where `D` used to be derived from `B`, but someone refactored the hierarchy.
|
||||||
|
The C-style cast is dangerous because it can do any kind of conversion, depriving us of any protection from mistakes (now or in the future).
|
||||||
|
|
||||||
##### Note
|
##### Note
|
||||||
|
|
||||||
When converting between types with no information loss (e.g. from `float` to
|
When converting between types with no information loss (e.g. from `float` to
|
||||||
`double` or `int64` from `int32`), brace initialization may be used instead.
|
`double` or `int64` from `int32`), brace initialization may be used instead.
|
||||||
|
|
||||||
double d{some_float};
|
double d {some_float};
|
||||||
int64_t i{some_int32};
|
int64_t i {some_int32};
|
||||||
|
|
||||||
This makes it clear that the type conversion was intended and also prevents
|
This makes it clear that the type conversion was intended and also prevents
|
||||||
conversions between types that might result in loss of precision. (It is a
|
conversions between types that might result in loss of precision. (It is a
|
||||||
|
|||||||
Reference in New Issue
Block a user