Merge pull request #941 from tkruse/style-fixes

Style fixes
This commit is contained in:
Gabriel Dos Reis 2017-06-02 09:17:40 -07:00 committed by GitHub
commit 4359ca5ae5

View File

@ -853,7 +853,7 @@ We could check earlier and improve the code:
// ... // ...
} }
Now, `m<=n` can be checked at the point of call (early) rather than later. Now, `m <= n` can be checked at the point of call (early) rather than later.
If all we had was a typo so that we meant to use `n` as the bound, the code could be further simplified (eliminating the possibility of an error): If all we had was a typo so that we meant to use `n` as the bound, the code could be further simplified (eliminating the possibility of an error):
void use3(int m) void use3(int m)
@ -1874,7 +1874,7 @@ Note: `length()` is, of course, `std::strlen()` in disguise.
Consider: Consider:
void copy_n(const T* p, T* q, int n); // copy from [p:p+n) to [q:q+n) void copy_n(const T* p, T* q, int n); // copy from [p:p + n) to [q:q + n)
What if there are fewer than `n` elements in the array pointed to by `q`? Then, we overwrite some probably unrelated memory. What if there are fewer than `n` elements in the array pointed to by `q`? Then, we overwrite some probably unrelated memory.
What if there are fewer than `n` elements in the array pointed to by `p`? Then, we read some probably unrelated memory. What if there are fewer than `n` elements in the array pointed to by `p`? Then, we read some probably unrelated memory.
@ -1964,13 +1964,14 @@ Having many arguments opens opportunities for confusion. Passing lots of argumen
The two most common reasons why functions have too many parameters are: The two most common reasons why functions have too many parameters are:
1. *Missing an abstraction.* There is an abstraction missing, so that a compound value is being 1. *Missing an abstraction.*
There is an abstraction missing, so that a compound value is being
passed as individual elements instead of as a single object that enforces an invariant. passed as individual elements instead of as a single object that enforces an invariant.
This not only expands the parameter list, but it leads to errors because the component values This not only expands the parameter list, but it leads to errors because the component values
are no longer protected by an enforced invariant. are no longer protected by an enforced invariant.
2. *Violating "one function, one responsibility."* The function is trying to do more than one 2. *Violating "one function, one responsibility."*
job and should probably be refactored. The function is trying to do more than one job and should probably be refactored.
##### Example ##### Example
@ -2040,13 +2041,13 @@ Adjacent arguments of the same type are easily swapped by mistake.
Consider: Consider:
void copy_n(T* p, T* q, int n); // copy from [p:p+n) to [q:q+n) void copy_n(T* p, T* q, int n); // copy from [p:p + n) to [q:q + n)
This is a nasty variant of a K&R C-style interface. It is easy to reverse the "to" and "from" arguments. This is a nasty variant of a K&R C-style interface. It is easy to reverse the "to" and "from" arguments.
Use `const` for the "from" argument: Use `const` for the "from" argument:
void copy_n(const T* p, T* q, int n); // copy from [p:p+n) to [q:q+n) void copy_n(const T* p, T* q, int n); // copy from [p:p + n) to [q:q + n)
##### Exception ##### Exception
@ -2389,8 +2390,8 @@ Functions with complex control structures are more likely to be long and more li
Consider: Consider:
double simpleFunc(double val, int flag1, int flag2) double simple_func(double val, int flag1, int flag2)
// simpleFunc: takes a value and calculates the expected ASIC output, // simple_func: takes a value and calculates the expected ASIC output,
// given the two mode flags. // given the two mode flags.
{ {
double intermediate; double intermediate;
@ -2433,8 +2434,8 @@ We can refactor:
// ??? // ???
} }
double simpleFunc(double val, int flag1, int flag2) double simple_func(double val, int flag1, int flag2)
// simpleFunc: takes a value and calculates the expected ASIC output, // simple_func: takes a value and calculates the expected ASIC output,
// given the two mode flags. // given the two mode flags.
{ {
if (flag1 > 0) if (flag1 > 0)
@ -3191,7 +3192,7 @@ Informal/non-explicit ranges are a source of errors.
##### Note ##### Note
Ranges are extremely common in C++ code. Typically, they are implicit and their correct use is very hard to ensure. Ranges are extremely common in C++ code. Typically, they are implicit and their correct use is very hard to ensure.
In particular, given a pair of arguments `(p, n)` designating an array \[`p`:`p+n`), In particular, given a pair of arguments `(p, n)` designating an array \[`p`:`p + n`),
it is in general impossible to know if there really are `n` elements to access following `*p`. it is in general impossible to know if there really are `n` elements to access following `*p`.
`span<T>` and `span_p<T>` are simple helper classes designating a \[`p`:`q`) range and a range starting with `p` and ending with the first element for which a predicate is true, respectively. `span<T>` and `span_p<T>` are simple helper classes designating a \[`p`:`q`) range and a range starting with `p` and ending with the first element for which a predicate is true, respectively.
@ -4186,7 +4187,7 @@ For example, a derived class might be allowed to skip a run-time check because i
int mem(int x, int y) int mem(int x, int y)
{ {
/* ... do something ... */ /* ... do something ... */
return do_bar(x+y); // OK: derived class can bypass check return do_bar(x + y); // OK: derived class can bypass check
} }
} }
@ -7167,7 +7168,7 @@ Without a using declaration, member functions in the derived class hide the enti
}; };
class D: public B { class D: public B {
public: public:
int f(int i) override { std::cout << "f(int): "; return i+1; } int f(int i) override { std::cout << "f(int): "; return i + 1; }
}; };
int main() int main()
{ {
@ -7180,7 +7181,7 @@ Without a using declaration, member functions in the derived class hide the enti
class D: public B { class D: public B {
public: public:
int f(int i) override { std::cout << "f(int): "; return i+1; } int f(int i) override { std::cout << "f(int): "; return i + 1; }
using B::f; // exposes f(double) using B::f; // exposes f(double)
}; };
@ -10384,17 +10385,17 @@ Readability and safety.
As an optimization, you may want to reuse a buffer as a scratch pad, but even then prefer to limit the variable's scope as much as possible and be careful not to cause bugs from data left in a recycled buffer as this is a common source of security bugs. As an optimization, you may want to reuse a buffer as a scratch pad, but even then prefer to limit the variable's scope as much as possible and be careful not to cause bugs from data left in a recycled buffer as this is a common source of security bugs.
{ void write_to_file() {
std::string buffer; // to avoid reallocations on every loop iteration std::string buffer; // to avoid reallocations on every loop iteration
for (auto& o : objects) for (auto& o : objects)
{ {
// First part of the work. // First part of the work.
generateFirstString(buffer, o); generate_first_String(buffer, o);
writeToFile(buffer); write_to_file(buffer);
// Second part of the work. // Second part of the work.
generateSecondString(buffer, o); generate_second_string(buffer, o);
writeToFile(buffer); write_to_file(buffer);
// etc... // etc...
} }
@ -11060,11 +11061,11 @@ There are exceedingly clever used of this "idiom", but they are far rarer than t
##### Note ##### Note
Unnamed function arguments are fine. Unnamed function arguments are fine.
##### Enforcement ##### Enforcement
Flag statements that are just a temporary Flag statements that are just a temporary
### <a name="Res-empty"></a>ES.85: Make empty statements visible ### <a name="Res-empty"></a>ES.85: Make empty statements visible
@ -12260,7 +12261,7 @@ can be surprising for many programmers.
##### Reason ##### Reason
Because most arithmetic is assumed to be signed; Because most arithmetic is assumed to be signed;
`x-y` yields a negative number when `y>x` except in the rare cases where you really want modulo arithmetic. `x - y` yields a negative number when `y > x` except in the rare cases where you really want modulo arithmetic.
##### Example ##### Example
@ -12270,7 +12271,7 @@ This is even more true for mixed signed and unsigned arithmetic.
template<typename T, typename T2> template<typename T, typename T2>
T subtract(T x, T2 y) T subtract(T x, T2 y)
{ {
return x-y; return x - y;
} }
void test() void test()
@ -12281,12 +12282,12 @@ This is even more true for mixed signed and unsigned arithmetic.
cout << subtract(us, 7u) << '\n'; // 4294967294 cout << subtract(us, 7u) << '\n'; // 4294967294
cout << subtract(s, 7u) << '\n'; // -2 cout << subtract(s, 7u) << '\n'; // -2
cout << subtract(us, 7) << '\n'; // 4294967294 cout << subtract(us, 7) << '\n'; // 4294967294
cout << subtract(s, us+2) << '\n'; // -2 cout << subtract(s, us + 2) << '\n'; // -2
cout << subtract(us, s+2) << '\n'; // 4294967294 cout << subtract(us, s + 2) << '\n'; // 4294967294
} }
Here we have been very explicit about what's happening, Here we have been very explicit about what's happening,
but if you had seen `us-(s+2)` or `s+=2; ... us-s`, would you reliably have suspected that the result would print as `4294967294`? but if you had seen `us - (s + 2)` or `s += 2; ...; us - s`, would you reliably have suspected that the result would print as `4294967294`?
##### Exception ##### Exception
@ -12301,10 +12302,10 @@ The build-in array uses signed types for subscripts.
This makes surprises (and bugs) inevitable. This makes surprises (and bugs) inevitable.
int a[10]; int a[10];
for (int i=0; i < 10; ++i) a[i]=i; for (int i = 0; i < 10; ++i) a[i] = i;
vector<int> v(10); vector<int> v(10);
// compares signed to unsigned; some compilers warn // compares signed to unsigned; some compilers warn
for (int i=0; v.size() < 10; ++i) v[i]=i; for (int i = 0; v.size() < 10; ++i) v[i] = i;
int a2[-2]; // error: negative size int a2[-2]; // error: negative size
@ -12491,13 +12492,13 @@ To enable better error detection.
vector<int> vec {1, 2, 3, 4, 5}; vector<int> vec {1, 2, 3, 4, 5};
for (int i=0; i < vec.size(); i+=2) // mix int and unsigned for (int i = 0; i < vec.size(); i += 2) // mix int and unsigned
cout << vec[i] << '\n'; cout << vec[i] << '\n';
for (unsigned i=0; i < vec.size(); i+=2) // risk wraparound for (unsigned i = 0; i < vec.size(); i += 2) // risk wraparound
cout << vec[i] << '\n'; cout << vec[i] << '\n';
for (vector<int>::size_type i=0; i < vec.size(); i+=2) // verbose for (vector<int>::size_type i = 0; i < vec.size(); i += 2) // verbose
cout << vec[i] << '\n'; cout << vec[i] << '\n';
for (auto i=0; i < vec.size(); i+=2) // mix int and unsigned for (auto i = 0; i < vec.size(); i += 2) // mix int and unsigned
cout << vec[i] << '\n'; cout << vec[i] << '\n';
##### Note ##### Note
@ -15249,7 +15250,7 @@ Exception specifications make error handling brittle, impose a run-time cost, an
// ... // ...
} }
if `f()` throws an exception different from `X` and `Y` the unexpected handler is invoked, which by default terminates. If `f()` throws an exception different from `X` and `Y` the unexpected handler is invoked, which by default terminates.
That's OK, but say that we have checked that this cannot happen and `f` is changed to throw a new exception `Z`, That's OK, but say that we have checked that this cannot happen and `f` is changed to throw a new exception `Z`,
we now have a crash on our hands unless we change `use()` (and re-test everything). we now have a crash on our hands unless we change `use()` (and re-test everything).
The snag is that `f()` may be in a library we do not control and the new exception is not anything that `use()` can do The snag is that `f()` may be in a library we do not control and the new exception is not anything that `use()` can do
@ -17939,11 +17940,11 @@ The argument-type error for `bar` cannot be caught until link time because of th
##### Example ##### Example
#include<string> #include <string>
#include<vector> #include <vector>
#include<iostream> #include <iostream>
#include<memory> #include <memory>
#include<algorithm> #include <algorithm>
using namespace std; using namespace std;
@ -17956,7 +17957,7 @@ could be distracting.
The use of `using namespace std;` leaves the programmer open to a name clash with a name from the standard library The use of `using namespace std;` leaves the programmer open to a name clash with a name from the standard library
#include<cmath> #include <cmath>
using namespace std; using namespace std;
int g(int x) int g(int x)
@ -18093,7 +18094,7 @@ but it is not required to do so by transitively including the entire `<string>`
resulting in the popular beginner question "why doesn't `getline(cin,s);` work?" resulting in the popular beginner question "why doesn't `getline(cin,s);` work?"
or even an occasional "`string`s cannot be compared with `==`). or even an occasional "`string`s cannot be compared with `==`).
The solution is to explicitly `#include<string>`: The solution is to explicitly `#include <string>`:
#include <iostream> #include <iostream>
#include <string> #include <string>
@ -18480,11 +18481,11 @@ Don't use C-style strings for operations that require non-trivial memory managem
{ {
int l1 = strlen(s1); int l1 = strlen(s1);
int l2 = strlen(s2); int l2 = strlen(s2);
char* p = (char*)malloc(l1+l2+2); char* p = (char*) malloc(l1 + l2 + 2);
strcpy(p, s1, l1); strcpy(p, s1, l1);
p[l1] = '.'; p[l1] = '.';
strcpy(p+l1+1, s2, l2); strcpy(p + l1 + 1, s2, l2);
p[l1+l2+1] = 0; p[l1 + l2 + 1] = 0;
return res; return res;
} }
@ -19375,7 +19376,7 @@ Enabling a profile is implementation defined; typically, it is set in the analys
To suppress enforcement of a profile check, place a `suppress` annotation on a language contract. For example: To suppress enforcement of a profile check, place a `suppress` annotation on a language contract. For example:
[[suppress(bounds)]] char* raw_find(char* p, int n, char x) // find x in p[0]..p[n-1] [[suppress(bounds)]] char* raw_find(char* p, int n, char x) // find x in p[0]..p[n - 1]
{ {
// ... // ...
} }
@ -19630,7 +19631,7 @@ These types allow the user to distinguish between owning and non-owning pointers
These "views" are never owners. These "views" are never owners.
References are never owners. Note: References have many opportunities to outlive the objects they refer to (returning a local variable by reference, holding a reference to an element of a vector and doing `push_back`, binding to `std::max(x,y+1)`, etc. The Lifetime safety profile aims to address those things, but even so `owner<T&>` does not make sense and is discouraged. References are never owners. Note: References have many opportunities to outlive the objects they refer to (returning a local variable by reference, holding a reference to an element of a vector and doing `push_back`, binding to `std::max(x, y + 1)`, etc. The Lifetime safety profile aims to address those things, but even so `owner<T&>` does not make sense and is discouraged.
The names are mostly ISO standard-library style (lower case and underscore): The names are mostly ISO standard-library style (lower case and underscore):
@ -19658,7 +19659,7 @@ If something is not supposed to be `nullptr`, say so:
* `not_null<T>` // `T` is usually a pointer type (e.g., `not_null<int*>` and `not_null<owner<Foo*>>`) that may not be `nullptr`. * `not_null<T>` // `T` is usually a pointer type (e.g., `not_null<int*>` and `not_null<owner<Foo*>>`) that may not be `nullptr`.
`T` can be any type for which `==nullptr` is meaningful. `T` can be any type for which `==nullptr` is meaningful.
* `span<T>` // `[`p`:`p+n`)`, constructor from `{p, q}` and `{p, n}`; `T` is the pointer type * `span<T>` // `[`p`:`p + n`)`, constructor from `{p, q}` and `{p, n}`; `T` is the pointer type
* `span_p<T>` // `{p, predicate}` \[`p`:`q`) where `q` is the first element for which `predicate(*p)` is true * `span_p<T>` // `{p, predicate}` \[`p`:`q`) where `q` is the first element for which `predicate(*p)` is true
* `string_span` // `span<char>` * `string_span` // `span<char>`
* `cstring_span` // `span<const char>` * `cstring_span` // `span<const char>`
@ -19695,7 +19696,7 @@ Use `not_null<zstring>` for C-style strings that cannot be `nullptr`. ??? Do we
These assertions are currently macros (yuck!) and must appear in function definitions (only) These assertions are currently macros (yuck!) and must appear in function definitions (only)
pending standard committee decisions on contracts and assertion syntax. pending standard committee decisions on contracts and assertion syntax.
See [the contract proposal](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0380r1.pdf); using the attribute syntax, See [the contract proposal](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0380r1.pdf); using the attribute syntax,
for example, `Expects(p!=nullptr)` will become `[[expects: p!=nullptr]]`. for example, `Expects(p != nullptr)` will become `[[expects: p != nullptr]]`.
## <a name="SS-utilities"></a>GSL.util: Utilities ## <a name="SS-utilities"></a>GSL.util: Utilities