* [F.15: Prefer simple and conventional ways of passing information](#Rf-conventional)
* [F.15: Prefer simple and conventional ways of passing information](#Rf-conventional)
* [F.16: For "in" parameters, pass cheaply-copied types by value and others by reference to `const`](#Rf-in)
* [F.16: For "in" parameters, pass cheaply-copied types by value and others by reference to `const`](#Rf-in)
* [F.17: For "in-out" parameters, pass by reference to non-`const`](#Rf-inout)
* [F.17: For "in-out" parameters, pass by reference to non-`const`](#Rf-inout)
* [F.18: For "consume" parameters, pass by `X&&` and `std::move` the parameter](#Rf-consume)
* [F.18: For "will-move-from" parameters, pass by `X&&` and `std::move` the parameter](#Rf-consume)
* [F.19: For "forward" parameters, pass by `TP&&` and only `std::forward` the parameter](#Rf-forward)
* [F.19: For "forward" parameters, pass by `TP&&` and only `std::forward` the parameter](#Rf-forward)
* [F.20: For "out" output values, prefer return values to output parameters](#Rf-out)
* [F.20: For "out" output values, prefer return values to output parameters](#Rf-out)
* [F.21: To return multiple "out" values, prefer returning a tuple or struct](#Rf-out-multi)
* [F.21: To return multiple "out" values, prefer returning a tuple or struct](#Rf-out-multi)
@ -2839,7 +2838,7 @@ For advanced uses (only), where you really need to optimize for rvalues passed t
* If the function is going to unconditionally move from the argument, take it by `&&`. See [F.18](#Rf-consume).
* If the function is going to unconditionally move from the argument, take it by `&&`. See [F.18](#Rf-consume).
* If the function is going to keep a copy of the argument, in addition to passing by `const&` (for lvalues),
* If the function is going to keep a copy of the argument, in addition to passing by `const&` (for lvalues),
add an overload that passes the parameter by `&&` (for rvalues) and in the body `std::move`s it to its destination. Essentially this overloads a "consume"; see [F.18](#Rf-consume).
add an overload that passes the parameter by `&&` (for rvalues) and in the body `std::move`s it to its destination. Essentially this overloads a "will-move-from"; see [F.18](#Rf-consume).
* In special cases, such as multiple "input + copy" parameters, consider using perfect forwarding. See [F.19](#Rf-forward).
* In special cases, such as multiple "input + copy" parameters, consider using perfect forwarding. See [F.19](#Rf-forward).
##### Example
##### Example
@ -2849,7 +2848,7 @@ For advanced uses (only), where you really need to optimize for rvalues passed t
// suffix is input-only but not as cheap as an int, pass by const&
// suffix is input-only but not as cheap as an int, pass by const&
void sink(unique_ptr<widget>); // input only, and consumes the widget
void sink(unique_ptr<widget>); // input only, and moves ownership of the widget
Avoid "esoteric techniques" such as:
Avoid "esoteric techniques" such as:
@ -2922,7 +2921,7 @@ A bad logic error can happen if the writer of `g()` incorrectly assumes the size
* (Moderate) ((Foundation)) Warn about functions regarding reference to non-`const` parameters that do *not* write to them.
* (Moderate) ((Foundation)) Warn about functions regarding reference to non-`const` parameters that do *not* write to them.
* (Simple) ((Foundation)) Warn when a non-`const` parameter being passed by reference is `move`d.
* (Simple) ((Foundation)) Warn when a non-`const` parameter being passed by reference is `move`d.
### <aname="Rf-consume"></a>F.18: For "consume" parameters, pass by `X&&` and `std::move` the parameter
### <aname="Rf-consume"></a>F.18: For "will-move-from" parameters, pass by `X&&` and `std::move` the parameter
##### Reason
##### Reason
@ -3198,6 +3197,8 @@ better
**See also**: [Support library](#S-gsl)
**See also**: [Support library](#S-gsl)
**See also**: [Do not pass an array as a single pointer](#Ri-array)
##### Enforcement
##### Enforcement
* (Simple) ((Bounds)) Warn for any arithmetic operation on an expression of pointer type that results in a value of pointer type.
* (Simple) ((Bounds)) Warn for any arithmetic operation on an expression of pointer type that results in a value of pointer type.
@ -4225,7 +4226,7 @@ For example:
// ...
// ...
private:
private:
double magnitude;
double magnitude;
double unit; // 1 is meters, 1000 is kilometers, 0.0001 is millimeters, etc.
double unit; // 1 is meters, 1000 is kilometers, 0.001 is millimeters, etc.
};
};
##### Note
##### Note
@ -5383,7 +5384,7 @@ If you really want an implicit conversion from the constructor argument type to
##### Note
##### Note
Copy and move constructors should not be made explicit because they do not perform conversions. Explicit copy/move constructors make passing and returning by value difficult.
Copy and move constructors should not be made `explicit` because they do not perform conversions. Explicit copy/move constructors make passing and returning by value difficult.
##### Enforcement
##### Enforcement
@ -6160,7 +6161,7 @@ A `unique_ptr` can be moved, but not copied. To achieve that its copy operations
auto pi3 {make()}; // OK, move: the result of make() is an rvalue
auto pi3 {make()}; // OK, move: the result of make() is an rvalue
}
}
Note that deleted methods should be public.
Note that deleted functions should be public.
##### Enforcement
##### Enforcement
@ -7562,7 +7563,7 @@ Contrast with [C.147](#Rh-ptr-cast), where failure is an error, and should not b
##### Example
##### Example
The example below describes the `add`method of a `Shape_owner` that takes ownership of constructed `Shape` objects. The objects are also sorted into views, according to their geometric attributes.
The example below describes the `add`function of a `Shape_owner` that takes ownership of constructed `Shape` objects. The objects are also sorted into views, according to their geometric attributes.
In this example, `Shape` does not inherit from `Geometric_attributes`. Only its subclasses do.
In this example, `Shape` does not inherit from `Geometric_attributes`. Only its subclasses do.
void add(Shape* const item)
void add(Shape* const item)
@ -9351,7 +9352,7 @@ Using `unique_ptr` in this way both documents and enforces the function call's o
##### Example
##### Example
void sink(unique_ptr<widget>); // consumes the widget
void sink(unique_ptr<widget>); // takes ownership of the widget
void uses(widget*); // just uses the widget
void uses(widget*); // just uses the widget
@ -16410,9 +16411,9 @@ Hard.
##### Example (using TS concepts)
##### Example (using TS concepts)
vector<string> v;
vector<string> v{ "abc", "xyz" };
auto& x = v.front(); // bad
auto& x = v.front(); // bad
String& s = v.begin(); // good (String is a GSL concept)
String& s = v.front(); // good (String is a GSL concept)
##### Enforcement
##### Enforcement
@ -17536,8 +17537,8 @@ Templating a class hierarchy that has many functions, especially many virtual fu
// ...
// ...
};
};
vector<int> vi;
Vector<int> vi;
vector<string> vs;
Vector<string> vs;
It is probably a dumb idea to define a `sort` as a member function of a container, but it is not unheard of and it makes a good example of what not to do.
It is probably a dumb idea to define a `sort` as a member function of a container, but it is not unheard of and it makes a good example of what not to do.
@ -17568,7 +17569,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[2]
p[1] = Pear{}; // put a Pear into p[1]
}
}
Apple aa [] = { an_apple, another_apple }; // aa contains Apples (obviously!)
Apple aa [] = { an_apple, another_apple }; // aa contains Apples (obviously!)
@ -17582,7 +17583,7 @@ If `sizeof(Apple) != sizeof(Pear)` the access to `aa[1]` will not be aligned to
We have a type violation and possibly (probably) a memory corruption.
We have a type violation and possibly (probably) a memory corruption.
Never write such code.
Never write such code.
Note that `maul()` violates the a `T*` points to an individual object [Rule](#???).
Note that `maul()` violates the a [`T*` points to an individual object rule](#Rf-ptr).
**Alternative**: Use a proper (templatized) container:
**Alternative**: Use a proper (templatized) container:
@ -17598,7 +17599,7 @@ Note that `maul()` violates the a `T*` points to an individual object [Rule](#??
Apple& a0 = &va[0]; // a Pear?
Apple& a0 = &va[0]; // a Pear?
Note that the assignment in `maul2()` violated the no-slicing [Rule](#???).
Note that the assignment in `maul2()` violated the [no-slicing rule](#Res-slice).
##### Enforcement
##### Enforcement
@ -17769,7 +17770,7 @@ The syntax and techniques needed are pretty horrendous.
##### Reason
##### Reason
Template metaprogramming is hard to get right, slows down compilation, and is often very hard to maintain.
Template metaprogramming is hard to get right, slows down compilation, and is often very hard to maintain.
However, there are real-world examples where template metaprogramming provides better performance that any alternative short of expert-level assembly code.
However, there are real-world examples where template metaprogramming provides better performance than any alternative short of expert-level assembly code.
Also, there are real-world examples where template metaprogramming expresses the fundamental ideas better than run-time code.
Also, there are real-world examples where template metaprogramming expresses the fundamental ideas better than run-time code.
For example, if you really need AST manipulation at compile time (e.g., for optional matrix operation folding) there may be no other way in C++.
For example, if you really need AST manipulation at compile time (e.g., for optional matrix operation folding) there may be no other way in C++.
@ -18211,6 +18212,7 @@ Source file rule summary:
* [SF.8: Use `#include` guards for all `.h` files](#Rs-guards)
* [SF.8: Use `#include` guards for all `.h` files](#Rs-guards)
* [SF.9: Avoid cyclic dependencies among source files](#Rs-cycles)
* [SF.9: Avoid cyclic dependencies among source files](#Rs-cycles)
* [SF.10: Avoid dependencies on implicitly `#include`d names](#Rs-implicit)
* [SF.10: Avoid dependencies on implicitly `#include`d names](#Rs-implicit)
* [SF.11: Header files should be self-contained](#Rs-contained)
* [SF.20: Use `namespace`s to express logical structure](#Rs-namespace)
* [SF.20: Use `namespace`s to express logical structure](#Rs-namespace)
* [SF.21: Don't use an unnamed (anonymous) namespace in a header](#Rs-unnamed)
* [SF.21: Don't use an unnamed (anonymous) namespace in a header](#Rs-unnamed)
@ -18618,6 +18620,27 @@ This rule against implicit inclusion is not meant to prevent such deliberate agg
Enforcement would require some knowledge about what in a header is meant to be "exported" to users and what is there to enable implementation.
Enforcement would require some knowledge about what in a header is meant to be "exported" to users and what is there to enable implementation.
No really good solution is possible until we have modules.
No really good solution is possible until we have modules.
### <aname="Rs-contained"></a>SF.11: Header files should be self-contained
##### Reason
Usability, headers should be simple to use and work when included on their own.
Headers should encapsulate the functionality they provide.
Avoid clients of a header having to manage that header's dependencies.
##### Example
#include "helpers.h"
// helpers.h depends on std::string and includes <string>
##### Note
Failing to follow this results in difficult to diagnose errors for clients of a header.
##### Enforcement
A test should verify that the header file itself compiles or that a cpp file which only includes the header file compiles.
### <aname="Rs-namespace"></a>SF.20: Use `namespace`s to express logical structure
### <aname="Rs-namespace"></a>SF.20: Use `namespace`s to express logical structure
##### Reason
##### Reason
@ -20160,7 +20183,7 @@ Naming and layout rules:
* [NL.7: Make the length of a name roughly proportional to the length of its scope](#Rl-name-length)
* [NL.7: Make the length of a name roughly proportional to the length of its scope](#Rl-name-length)
* [NL.8: Use a consistent naming style](#Rl-name)
* [NL.8: Use a consistent naming style](#Rl-name)
* [NL.9: Use `ALL_CAPS` for macro names only](#Rl-all-caps)
* [NL.9: Use `ALL_CAPS` for macro names only](#Rl-all-caps)