mirror of
https://github.com/isocpp/CppCoreGuidelines.git
synced 2025-12-18 05:04:41 +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
|
||||
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user