a few more fix-ups in ES.*

This commit is contained in:
Bjarne Stroustrup
2017-04-09 15:15:48 -04:00
parent 26d56a2f54
commit 6a3d61fd8d

View File

@@ -1,6 +1,6 @@
# <a name="main"></a>C++ Core Guidelines
April 4, 2017
April 9, 2017
Editors:
@@ -9770,19 +9770,16 @@ For containers, there is a tradition for using `{...}` for a list of elements an
##### 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
// x2 is an initializer_list<int> with an element 7
// (this will will change to "element 7" in C++17)
auto x2 = {7};
auto x2 = {7}; // x2 is an initializer_list<int> with an element 7
auto x11 {7, 8}; // error: two initializers
auto x22 = {7, 8}; // x2 is an initializer_list<int> with elements 7 and 8
##### Exception
Use `={...}` if you really want an `initializer_list<T>`
So 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
@@ -9826,12 +9823,16 @@ increases readability, and it has zero or near zero runtime cost.
{
auto p1 = make_unique<int>(7); // OK
int* p2 = new int{7}; // bad: might leak
// ...
// ... no assignment to p2 ...
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.
The same is the case when `at()` throws.
##### Enforcement
@@ -10373,6 +10374,7 @@ consider `gsl::finally()` as a cleaner and more reliable alternative to `goto ex
##### Reason
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
(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
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
@@ -10910,15 +10930,29 @@ The named casts are:
##### 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
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 d{some_float};
int64_t i{some_int32};
double d {some_float};
int64_t i {some_int32};
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