Align comments that were aligned by tabs.

This commit is contained in:
Michael Park
2015-12-11 16:26:12 -05:00
parent 1a850815d3
commit 06348247d9

View File

@@ -3193,10 +3193,10 @@ You need a reason (use cases) for using a hierarchy.
void use() void use()
{ {
Point1 p11 {1, 2}; // make an object on the stack Point1 p11 {1, 2}; // make an object on the stack
Point1 p12 {p11}; // a copy Point1 p12 {p11}; // a copy
auto p21 = make_unique<Point2>(1, 2); // make an object on the free store auto p21 = make_unique<Point2>(1, 2); // make an object on the free store
auto p22 = p21.clone(); // make a copy auto p22 = p21.clone(); // make a copy
// ... // ...
} }
@@ -3343,7 +3343,7 @@ It's the simplest and gives the cleanest semantics.
map<int, int> rep; map<int, int> rep;
}; };
Named_map nm; // default construct Named_map nm; // default construct
Named_map nm2 {nm}; // copy construct Named_map nm2 {nm}; // copy construct
Since `std::map` and `string` have all the special functions, no further work is needed. Since `std::map` and `string` have all the special functions, no further work is needed.
@@ -4245,7 +4245,7 @@ Makes it explicit that the same value is expected to be used in all constructors
int j; int j;
public: public:
X() :i{666}, s{"qqq"} { } // j is uninitialized X() :i{666}, s{"qqq"} { } // j is uninitialized
X(int ii) :i{ii} {} // s is "" and j is uninitialized X(int ii) :i{ii} {} // s is "" and j is uninitialized
// ... // ...
}; };
@@ -4258,7 +4258,7 @@ How would a maintainer know whether `j` was deliberately uninitialized (probably
string s {"qqq"}; string s {"qqq"};
int j {0}; int j {0};
public: public:
X2() = default; // all members are initialized to their defaults X2() = default; // all members are initialized to their defaults
X2(int ii) :i{ii} {} // s and j initialized to their defaults X2(int ii) :i{ii} {} // s and j initialized to their defaults
// ... // ...
}; };
@@ -4307,7 +4307,7 @@ An initialization explicitly states that initialization, rather than assignment,
class C { // UGLY, aka very bad class C { // UGLY, aka very bad
int* p; int* p;
public: public:
C() { cout << *p; p = new int{10}; } // accidental use before initialized C() { cout << *p; p = new int{10}; } // accidental use before initialized
// ... // ...
}; };
@@ -4481,7 +4481,7 @@ It is simple and efficient. If you want to optimize for rvalues, provide an over
Foo b; Foo b;
Foo f(); Foo f();
a = b; // assign lvalue: copy a = b; // assign lvalue: copy
a = f(); // assign rvalue: potentially move a = f(); // assign rvalue: potentially move
##### Note ##### Note
@@ -4540,7 +4540,7 @@ After a copy `x` and `y` can be independent objects (value semantics, the way no
public: public:
X(); X();
X(const X&); // copy X X(const X&); // copy X
void modify(); // change the value of X void modify(); // change the value of X
// ... // ...
~X() { delete[] p; } ~X() { delete[] p; }
private: private:
@@ -4692,7 +4692,7 @@ That is the generally assumed semantics. After `x=std::move(y)` the value of `x`
class X { // OK: value semantics class X { // OK: value semantics
public: public:
X(); X();
X(X&& a); // move X X(X&& a); // move X
void modify(); // change the value of X void modify(); // change the value of X
// ... // ...
~X() { delete[] p; } ~X() { delete[] p; }
@@ -4705,7 +4705,7 @@ That is the generally assumed semantics. After `x=std::move(y)` the value of `x`
X::X(X&& a) X::X(X&& a)
:p{a.p}, sz{a.sz} // steal representation :p{a.p}, sz{a.sz} // steal representation
{ {
a.p = nullptr; // set to "empty" a.p = nullptr; // set to "empty"
a.sz = 0; a.sz = 0;
} }
@@ -4806,7 +4806,7 @@ These copy operations do not throw.
template<typename T> template<typename T>
class Vector2 { class Vector2 {
// ... // ...
Vector2(Vector2&& a) { *this = a; } // just use the copy Vector2(Vector2&& a) { *this = a; } // just use the copy
Vector2& operator=(Vector2&& a) { *this = a; } // just use the copy Vector2& operator=(Vector2&& a) { *this = a; } // just use the copy
// ... // ...
public: public:
@@ -5387,8 +5387,8 @@ Readability. Detection of mistakes. Explicit `override` allows the compiler to c
}; };
struct D : B { struct D : B {
void f1(int); // warn: D::f1() hides B::f1() void f1(int); // warn: D::f1() hides B::f1()
void f2(int); // warn: no explicit override void f2(int); // warn: no explicit override
void f3(double); // warn: D::f3() hides B::f3() void f3(double); // warn: D::f3() hides B::f3()
// ... // ...
}; };
@@ -5884,7 +5884,7 @@ It also ensures exception safety in complex expressions.
unique_ptr<Foo> p {new<Foo>{7}}; // OK: but repetitive unique_ptr<Foo> p {new<Foo>{7}}; // OK: but repetitive
auto q = make_unique<Foo>(7); // Better: no repetition of Foo auto q = make_unique<Foo>(7); // Better: no repetition of Foo
// Not exception-safe: the compiler may interleave the computations of arguments as follows: // Not exception-safe: the compiler may interleave the computations of arguments as follows:
// //
@@ -5937,9 +5937,9 @@ Subscripting the resulting base pointer will lead to invalid object access and p
D a[] = { {1, 2}, {3, 4}, {5, 6} }; D a[] = { {1, 2}, {3, 4}, {5, 6} };
B* p = a; // bad: a decays to &a[0] which is converted to a B* B* p = a; // bad: a decays to &a[0] which is converted to a B*
p[1].x = 7; // overwrite D[0].y p[1].x = 7; // overwrite D[0].y
use(a); // bad: a decays to &a[0] which is converted to a B* use(a); // bad: a decays to &a[0] which is converted to a B*
##### Enforcement ##### Enforcement
@@ -6538,7 +6538,7 @@ We can fix that problem by making ownership explicit:
class X2 { class X2 {
// ... // ...
public: public:
owner<T> p; // OK: p is owning owner<T> p; // OK: p is owning
T* q; // OK: q is not owning T* q; // OK: q is not owning
}; };
@@ -6860,7 +6860,7 @@ Consider:
void f() void f()
{ {
X x; X x;
X* p1 { new X }; // see also ??? X* p1 { new X }; // see also ???
unique_ptr<T> p2 { new X }; // unique ownership; see also ??? unique_ptr<T> p2 { new X }; // unique ownership; see also ???
shared_ptr<T> p3 { new X }; // shared ownership; see also ??? shared_ptr<T> p3 { new X }; // shared ownership; see also ???
} }
@@ -7654,7 +7654,7 @@ No, `i = 7` does not initialize `i`; it assigns to it. Also, `i` can be read in
void use(int arg) // OK void use(int arg) // OK
{ {
int i = 7; // OK: initialized int i = 7; // OK: initialized
string s; // OK: default initialized string s; // OK: default initialized
// ... // ...
} }
@@ -7885,7 +7885,7 @@ The rules for `{}` initialization are simpler, more general, less ambiguous, and
For containers, there is a tradition for using `{...}` for a list of elements and `(...)` for sizes: For containers, there is a tradition for using `{...}` for a list of elements and `(...)` for sizes:
vector<int> v1(10); // vector of 10 elements with the default value 0 vector<int> v1(10); // vector of 10 elements with the default value 0
vector<int> v2 {10}; // vector of 1 element with the value 10 vector<int> v2 {10}; // vector of 1 element with the value 10
##### Note ##### Note
@@ -7933,9 +7933,9 @@ Use `={...}` if you really want an `initializer_list<T>`
void f() void f()
{ {
T x1(1); // T initialized with 1 T x1(1); // T initialized with 1
T x0(); // bad: function declaration (often a mistake) T x0(); // bad: function declaration (often a mistake)
T y1 {1}; // T initialized with 1 T y1 {1}; // T initialized with 1
T y0 {}; // default initialized T T y0 {}; // default initialized T
// ... // ...
} }
@@ -7960,7 +7960,7 @@ Using `std::unique_ptr` is the simplest way to avoid leaks. And it is free compa
void use(bool leak) void use(bool leak)
{ {
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
// ... // ...
if (leak) return; if (leak) return;
// ... // ...
@@ -8225,8 +8225,8 @@ Statements control the flow of control (except for function calls and exception
void use(int n) void use(int n)
{ {
switch (n) { // good switch (n) { // good
case 0: // ... case 0: // ...
case 7: // ... case 7: // ...
} }
} }
@@ -8725,7 +8725,7 @@ A key example is basic narrowing:
The guideline support library offers a `narrow` operation for specifying that narrowing is acceptable and a `narrow` ("narrow if") that throws an exception if a narrowing would throw away information: The guideline support library offers a `narrow` operation for specifying that narrowing is acceptable and a `narrow` ("narrow if") that throws an exception if a narrowing would throw away information:
i = narrow_cast<int>(d); // OK (you asked for it): narrowing: i becomes 7 i = narrow_cast<int>(d); // OK (you asked for it): narrowing: i becomes 7
i = narrow<int>(d); // OK: throws narrowing_error i = narrow<int>(d); // OK: throws narrowing_error
We also include lossy arithmetic casts, such as from a negative floating point type to an unsigned integral type: We also include lossy arithmetic casts, such as from a negative floating point type to an unsigned integral type:
@@ -8756,8 +8756,8 @@ Consider:
void f(int); void f(int);
void f(char*); void f(char*);
f(0); // call f(int) f(0); // call f(int)
f(nullptr); // call f(char*) f(nullptr); // call f(char*)
##### Enforcement ##### Enforcement
@@ -8809,10 +8809,10 @@ The named casts are:
* `const_cast` * `const_cast`
* `reinterpret_cast` * `reinterpret_cast`
* `dynamic_cast` * `dynamic_cast`
* `std::move` // `move(x)` is an rvalue reference to `x` * `std::move` // `move(x)` is an rvalue reference to `x`
* `std::forward` // `forward(x)` is an rvalue reference to `x` * `std::forward` // `forward(x)` is an rvalue reference to `x`
* `gsl::narrow_cast` // `narrow_cast<T>(x)` is `static_cast<T>(x)` * `gsl::narrow_cast` // `narrow_cast<T>(x)` is `static_cast<T>(x)`
* `gsl::narrow` // `narrow<T>(x)` is `static_cast<T>(x)` if `static_cast<T>(x) == x` or it throws `narrowing_error` * `gsl::narrow` // `narrow<T>(x)` is `static_cast<T>(x)` if `static_cast<T>(x) == x` or it throws `narrowing_error`
##### Example ##### Example
@@ -8902,7 +8902,7 @@ That's what the language requires and mistakes can lead to resource release erro
{ {
auto p = new X[n]; // n default constructed Xs auto p = new X[n]; // n default constructed Xs
// ... // ...
delete p; // error: just delete the object p, rather than delete the array p[] delete p; // error: just delete the object p, rather than delete the array p[]
} }
##### Note ##### Note
@@ -10402,7 +10402,7 @@ Hard.
##### Example ##### Example
vector<string> v; vector<string> v;
auto& x = v.front(); // bad auto& x = v.front(); // bad
String& s = v.begin(); // good String& s = v.begin(); // good
##### Enforcement ##### Enforcement
@@ -10421,12 +10421,12 @@ To say "`T` is `Sortable`":
template<typename T> // Correct but verbose: "The parameter is template<typename T> // Correct but verbose: "The parameter is
requires Sortable<T> // of type T which is the name of a type requires Sortable<T> // of type T which is the name of a type
void sort(T&); // that is Sortable" void sort(T&); // that is Sortable"
template<Sortable T> // Better: "The parameter is of type T template<Sortable T> // Better: "The parameter is of type T
void sort(T&); // which is Sortable" void sort(T&); // which is Sortable"
void sort(Sortable&); // Best: "The parameter is Sortable" void sort(Sortable&); // Best: "The parameter is Sortable"
The shorter versions better match the way we speak. Note that many templates don't need to use the `template` keyword. The shorter versions better match the way we speak. Note that many templates don't need to use the `template` keyword.
@@ -10460,7 +10460,7 @@ and should be used only as building blocks for meaningful concepts, rather than
int x = 7; int x = 7;
int y = 9; int y = 9;
auto z = plus(x, y); // z = 16 auto z = plus(x, y); // z = 16
string xx = "7"; string xx = "7";
string yy = "9"; string yy = "9";
@@ -10490,7 +10490,7 @@ The ability to specify a meaningful semantics is a defining characteristic of a
int x = 7; int x = 7;
int y = 9; int y = 9;
auto z = plus(x, y); // z = 18 auto z = plus(x, y); // z = 18
string xx = "7"; string xx = "7";
string yy = "9"; string yy = "9";
@@ -10701,14 +10701,14 @@ In general, passing function objects give better performance than passing pointe
##### Example ##### Example
bool greater(double x, double y) { return x>y; } bool greater(double x, double y) { return x>y; }
sort(v, greater); // pointer to function: potentially slow sort(v, greater); // pointer to function: potentially slow
sort(v, [](double x, double y) { return x>y; }); // function object sort(v, [](double x, double y) { return x>y; }); // function object
sort(v, greater<>); // function object sort(v, greater<>); // function object
bool greater_than_7(double x) { return x>7; } bool greater_than_7(double x) { return x>7; }
auto x = find_if(v, greater_than_7); // pointer to function: inflexible auto x = find_if(v, greater_than_7); // pointer to function: inflexible
auto y = find_if(v, [](double x) { return x>7; }); // function object: carries the needed data auto y = find_if(v, [](double x) { return x>7; }); // function object: carries the needed data
auto y = find_if(v, Greater_than<double>(7)); // function object: carries the needed data auto y = find_if(v, Greater_than<double>(7)); // function object: carries the needed data
??? these lambdas are crying out for auto parameters -- any objection to making the change? ??? these lambdas are crying out for auto parameters -- any objection to making the change?
@@ -10786,7 +10786,7 @@ Uniformity: `using` is syntactically similar to `auto`.
##### Example ##### Example
typedef int (*PFI)(int); // OK, but convoluted typedef int (*PFI)(int); // OK, but convoluted
using PFI2 = int (*)(int); // OK, preferred using PFI2 = int (*)(int); // OK, preferred
@@ -10794,7 +10794,7 @@ Uniformity: `using` is syntactically similar to `auto`.
typedef int (*PFT)(T); // error typedef int (*PFT)(T); // error
template<typename T> template<typename T>
using PFT2 = int (*)(T); // OK using PFT2 = int (*)(T); // OK
##### Enforcement ##### Enforcement
@@ -11182,7 +11182,7 @@ Assume that `Apple` and `Pear` are two kinds of `Fruit`s.
void maul(Fruit* p) void maul(Fruit* p)
{ {
*p = Pear{}; // put a Pear into *p *p = Pear{}; // put a Pear into *p
p[1] = Pear{}; // put a Pear into p[1] p[1] = Pear{}; // put a Pear into p[1]
} }
@@ -11276,13 +11276,13 @@ It could be a base class:
Link* pre; Link* pre;
}; };
template<typename T> // templated wrapper to add type safety template<typename T> // templated wrapper to add type safety
struct Link : Link_base { struct Link : Link_base {
T val; T val;
}; };
struct List_base { struct List_base {
Link_base* first; // first element (if any) Link_base* first; // first element (if any)
int sz; // number of elements int sz; // number of elements
void add_front(Link_base* p); void add_front(Link_base* p);
// ... // ...
@@ -11292,7 +11292,7 @@ It could be a base class:
class List : List_base { class List : List_base {
public: public:
void put_front(const T& e) { add_front(new Link<T>{e}); } // implicit cast to Link_base void put_front(const T& e) { add_front(new Link<T>{e}); } // implicit cast to Link_base
T& front() { static_cast<Link<T>*>(first).val; } // explicit cast back to Link<T> T& front() { static_cast<Link<T>*>(first).val; } // explicit cast back to Link<T>
// ... // ...
}; };
@@ -11668,7 +11668,7 @@ It provides better support for high-level programming and often generates faster
char ch = 7; char ch = 7;
void* pv = &ch; void* pv = &ch;
int* pi = pv; // not C++ int* pi = pv; // not C++
*pi = 999; // overwrite sizeof(int) bytes near &ch *pi = 999; // overwrite sizeof(int) bytes near &ch
##### Enforcement ##### Enforcement
@@ -12783,10 +12783,10 @@ References are never owners.
The names are mostly ISO standard-library style (lower case and underscore): The names are mostly ISO standard-library style (lower case and underscore):
* `T*` // The `T*` is not an owner, may be null; assumed to be pointing to a single element. * `T*` // The `T*` is not an owner, may be null; assumed to be pointing to a single element.
* `char*` // A C-style string (a zero-terminated array of characters); may be null. * `char*` // A C-style string (a zero-terminated array of characters); may be null.
* `const char*` // A C-style string; may be null. * `const char*` // A C-style string; may be null.
* `T&` // The `T&` is not an owner and can never be a "null reference"; references are always bound to objects. * `T&` // The `T&` is not an owner and can never be a "null reference"; references are always bound to objects.
The "raw-pointer" notation (e.g. `int*`) is assumed to have its most common meaning; that is, a pointer points to an object, but does not own it. The "raw-pointer" notation (e.g. `int*`) is assumed to have its most common meaning; that is, a pointer points to an object, but does not own it.
Owners should be converted to resource handles (e.g., `unique_ptr` or `vector<T>`) or marked `owner<T*>` Owners should be converted to resource handles (e.g., `unique_ptr` or `vector<T>`) or marked `owner<T*>`
@@ -12807,13 +12807,13 @@ An `owner<T>` is assumed to refer to an object on the free store (heap).
If something is not supposed to be `nullptr`, say so: 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>`
A `span<T>` refers to zero or more mutable `T`s unless `T` is a `const` type. A `span<T>` refers to zero or more mutable `T`s unless `T` is a `const` type.
@@ -12822,7 +12822,7 @@ A `char*` that points to something that is not a C-style string (e.g., a pointer
There is no really good way to say "pointer to a single `char`" (`string_span{p, 1}` can do that, and `T*` where `T` is a `char` in a template that has not been specialized for C-style strings). There is no really good way to say "pointer to a single `char`" (`string_span{p, 1}` can do that, and `T*` where `T` is a `char` in a template that has not been specialized for C-style strings).
* `zstring` // a `char*` supposed to be a C-style string; that is, a zero-terminated sequence of `char` or `null_ptr` * `zstring` // a `char*` supposed to be a C-style string; that is, a zero-terminated sequence of `char` or `null_ptr`
* `czstring` // a `const char*` supposed to be a C-style string; that is, a zero-terminated sequence of `const` `char` or `null_ptr` * `czstring` // a `const char*` supposed to be a C-style string; that is, a zero-terminated sequence of `const` `char` or `null_ptr`
Logically, those last two aliases are not needed, but we are not always logical, and they make the distinction between a pointer to one `char` and a pointer to a C-style string explicit. Logically, those last two aliases are not needed, but we are not always logical, and they make the distinction between a pointer to one `char` and a pointer to a C-style string explicit.
A sequence of characters that is not assumed to be zero-terminated should be a `char*`, rather than a `zstring`. A sequence of characters that is not assumed to be zero-terminated should be a `char*`, rather than a `zstring`.
@@ -12849,11 +12849,11 @@ These assertions is currently macros (yuck!) pending standard commission decisio
## <a name="SS-utilities"></a> GSL.util: Utilities ## <a name="SS-utilities"></a> GSL.util: Utilities
* `finally` // `finally(f)` makes a `final_action{f}` with a destructor that invokes `f` * `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_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` * `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. * `[[implicit]]` // "Marker" to put on single-argument constructors to explicitly make them non-explicit.
* `move_owner` // `p = move_owner(q)` means `p = q` but ??? * `move_owner` // `p = move_owner(q)` means `p = q` but ???
## <a name="SS-gsl-concepts"></a> GSL.concept: Concepts ## <a name="SS-gsl-concepts"></a> GSL.concept: Concepts
@@ -13896,7 +13896,7 @@ To avoid extremely hard-to-find errors. Dereferencing such a pointer is undefine
string* p = bad(); string* p = bad();
vector<int> xx = {7, 8, 9}; vector<int> xx = {7, 8, 9};
string x = *p; // undefined behavior: x may not be 1 string x = *p; // undefined behavior: x may not be 1
*p = "Evil!"; // undefined behavior: we don't know what (if anything) is allocated a location p *p = "Evil!"; // undefined behavior: we don't know what (if anything) is allocated a location p
} }
The `string`s of `v` are destroyed upon exit from `bad()` and so is `v` itself. The returned pointer points to unallocated memory on the free store. This memory (pointed into by `p`) may have been reallocated by the time `*p` is executed. There may be no `string` to read and a write through `p` could easily corrupt objects of unrelated types. The `string`s of `v` are destroyed upon exit from `bad()` and so is `v` itself. The returned pointer points to unallocated memory on the free store. This memory (pointed into by `p`) may have been reallocated by the time `*p` is executed. There may be no `string` to read and a write through `p` could easily corrupt objects of unrelated types.