* Add gsl::index, closes#1098
And update examples throughout to use `index` as appropriate
* Actually adding `index` to the GSL.util section
* Added `sizeof` to whitelisted signed/unsigned comparisons
Same reason as container `.size()` -- better backward compatibility with
the existing standard
for (int i = 1; i <v.size();++i)//touchestwoelements:can'tbearange-for
for (gsl::index i = 1; i <v.size();++i)//touchestwoelements:can'tbearange-for
cout <<v[i]+v[i-1]<<'\n';
for (int i = 0; i <v.size();++i)//possiblesideeffect:can'tbearange-for
for (gsl::index i = 0; i <v.size();++i)//possiblesideeffect:can'tbearange-for
cout <<f(v,&v[i])<<'\n';
for (int i = 0; i <v.size();++i){//bodymesseswithloopvariable:can'tbearange-for
for (gsl::index i = 0; i <v.size();++i){//bodymesseswithloopvariable:can'tbearange-for
if (i % 2 == 0)
continue; // skip even elements
else
@ -12027,7 +12029,7 @@ Readability: the complete logic of the loop is visible "up front". The scope of
##### Example
for (int i = 0; i <vec.size();i++){
for (gsl::index i = 0; i <vec.size();i++){
// do work
}
@ -12526,11 +12528,13 @@ It is harder to spot the problem in more realistic examples.
##### Note
Unfortunately, C++ uses signed integers for array subscripts and the standard library uses unsigned integers for container subscripts.
This precludes consistency.
This precludes consistency. Use `gsl::index` for subscripts; [see ES.107](#Res-subscripts).
##### Enforcement
Compilers already know and sometimes warn.
* Compilers already know and sometimes warn.
* (To avoid noise) Do not flag on a mixed signed/unsigned comparison where one of the arguments is `sizeof` or a call to container `.size()` and the other is `ptrdiff_t`.
### <aname="Res-unsigned"></a>ES.101: Use unsigned types for bit manipulation
@ -12597,25 +12601,29 @@ is going to be surprising for many programmers.
##### Example
The standard library uses unsigned types for subscripts.
The build-in array uses signed types for subscripts.
The built-in array uses signed types for subscripts.
This makes surprises (and bugs) inevitable.
int a[10];
for (int i = 0; i <10;++i)a[i]=i;
vector<int> v(10);
// compares signed to unsigned; some compilers warn
for (int i = 0; v.size() <10;++i)v[i]=i;
// compares signed to unsigned; some compilers warn, but we should not
for (gsl::index i = 0; v.size() <10;++i)v[i]=i;
int a2[-2]; // error: negative size
// OK, but the number of ints (4294967294) is so large that we should get an exception
vector<int> v2(-2);
Use `gsl::index` for subscripts; [see ES.107](#Res-subscripts).
##### Enforcement
* Flag mixed signed and unsigned arithmetic
* Flag results of unsigned arithmetic assigned to or printed as signed.
* Flag unsigned literals (e.g. `-2`) used as container subscripts.
* (To avoid noise) Do not flag on a mixed signed/unsigned comparison where one of the arguments is `sizeof` or a call to container `.size()` and the other is `ptrdiff_t`.
Hard: there is a lot of code using `unsigned` and we don't offer a practical positive number type.
### <aname="Res-subscripts"></a>ES.107: Don't use `unsigned` for subscripts
### <aname="Res-subscripts"></a>ES.107: Don't use `unsigned` for subscripts, prefer `gsl::index`
##### Reason
To avoid signed/unsigned confusion.
To enable better optimization.
To enable better error detection.
To avoid the pitfalls with `auto` and `int`.
##### Example, bad
vector<int> vec {1, 2, 3, 4, 5};
vector<int> vec = /*...*/;
for (int i = 0; i <vec.size();i+=2)//mix intandunsigned
for (int i = 0; i <vec.size();i+=2)//may notbebigenough
cout <<vec[i]<<'\n';
for (unsigned i = 0; i <vec.size();i+=2)//riskwraparound
cout <<vec[i]<<'\n';
for (auto i = 0; i <vec.size();i+=2)//maynotbebigenough
cout <<vec[i]<<'\n';
for (vector<int>::size_type i = 0; i <vec.size();i+=2)//verbose
cout <<vec[i]<<'\n';
for (auto i = 0; i <vec.size();i+=2)//mixintandunsigned
for (auto i = vec.size()-1; i >= 0; i -= 2) // bug
cout <<vec[i]<<'\n';
for (int i = vec.size()-1; i >= 0; i -= 2) // may not be big enough
cout <<vec[i]<<'\n';
##### Example, good
vector<int> vec = /*...*/;
for (gsl::index i = 0; i <vec.size();i+=2)//ok
cout <<vec[i]<<'\n';
for (gsl::index i = vec.size()-1; i >= 0; i -= 2) // ok
cout <<vec[i]<<'\n';
##### Note
The built-in array uses signed subscripts.
The standard-library containers use unsigned subscripts.
Thus, no perfect and fully compatible solution is possible.
Given the known problems with unsigned and signed/unsigned mixtures, better stick to (signed) integers.
Thus, no perfect and fully compatible solution is possible (unless and until the standard-library containers change to use signed subscripts someday in the future).
Given the known problems with unsigned and signed/unsigned mixtures, better stick to (signed) integers of a sufficient size, which is guaranteed by `gsl::index`.
##### Example
@ -12813,7 +12835,7 @@ Given the known problems with unsigned and signed/unsigned mixtures, better stic
struct My_container {
public:
// ...
T& operator[](int i); // not unsigned
T& operator[](gsl::index i); // not unsigned
// ...
};
@ -12831,7 +12853,11 @@ Alternatives for users
##### Enforcement
Very tricky as long as the standard-library containers get it wrong.
* Very tricky as long as the standard-library containers get it wrong.
* (To avoid noise) Do not flag on a mixed signed/unsigned comparison where one of the arguments is `sizeof` or a call to container `.size()` and the other is `ptrdiff_t`.
# <aname="S-performance"></a>Per: Performance
@ -14808,7 +14834,7 @@ C++ implementations tend to be optimized based on the assumption that exceptions
int find_index(vector<string>& vec, const string& x)
{
try {
for (int i = 0; i <vec.size();++i)
for (gsl::index i = 0; i <vec.size();++i)
if (vec[i] == x) throw i; // found x
} catch (int i) {
return i;
@ -19996,12 +20022,13 @@ for example, `Expects(p != nullptr)` will become `[[expects: p != nullptr]]`.
## <aname="SS-utilities"></a>GSL.util: Utilities
* `finally` // `finally(f)` makes a `final_action{f}` with a destructor that invokes `f`
* `narrow_cast` // `narrow_cast<T>(x)` is `static_cast<T>(x)`
* `narrow` // `narrow<T>(x)` is `static_cast<T>(x)` if `static_cast<T>(x) == x` or it throws `narrowing_error`
* `[[implicit]]` // "Marker" to put on single-argument constructors to explicitly make them non-explicit.
* `move_owner` // `p = move_owner(q)` means `p = q` but ???
* `finally`// `finally(f)` makes a `final_action{f}` with a destructor that invokes `f`
* `narrow_cast`// `narrow_cast<T>(x)` is `static_cast<T>(x)`
* `narrow`// `narrow<T>(x)` is `static_cast<T>(x)` if `static_cast<T>(x) == x` or it throws `narrowing_error`
* `[[implicit]]`// "Marker" to put on single-argument constructors to explicitly make them non-explicit.
* `move_owner`// `p = move_owner(q)` means `p = q` but ???
* `joining_thread` // a RAII style version of `std::thread` that joins.
* `index` // a type to use for all container and array indexing (currently an alias for `ptrdiff_t`)