Merge pull request #278 from tkruse/fix-mdstyle19

Text Style: Unnecessary blank, puntuation, linebreak after comma
This commit is contained in:
Gabriel Dos Reis
2015-10-05 03:54:10 -07:00

View File

@@ -96,8 +96,7 @@ In other words, what would you like your code to look like in 5 years' time, giv
The guidelines are focused on relatively higher-level issues, such as interfaces, resource management, memory management, and concurrency. The guidelines are focused on relatively higher-level issues, such as interfaces, resource management, memory management, and concurrency.
Such rules affect application architecture and library design. Such rules affect application architecture and library design.
Following the rules will lead to code that is statically type safe, Following the rules will lead to code that is statically type safe, has no resource leaks, and catches many more programming logic errors than is common in code today.
has no resource leaks, and catches many more programming logic errors than is common in code today.
And it will run fast - you can afford to do things right. And it will run fast - you can afford to do things right.
We are less concerned with low-level issues, such as naming conventions and indentation style. We are less concerned with low-level issues, such as naming conventions and indentation style.
@@ -148,14 +147,8 @@ All C++ programmers. This includes [programmers who might consider C](#S-cpl).
The purpose of this document is to help developers to adopt modern C++ (C++11, C++14, and soon C++17) and to achieve a more uniform style across code bases. The purpose of this document is to help developers to adopt modern C++ (C++11, C++14, and soon C++17) and to achieve a more uniform style across code bases.
We do not suffer the delusion that every one of these rules can be effectively applied to every code base. We do not suffer the delusion that every one of these rules can be effectively applied to every code base. Upgrading old systems is hard. However, we do believe that a program that uses a rule is less error-prone and more maintainable than one that does not. Often, rules also lead to faster/easier initial development.
Upgrading old systems is hard. As far as we can tell, these rules lead to code that performs as well or better than older, more conventional techniques; they are meant to follow the zero-overhead principle ("what you don't use, you don't pay for" or "when you use an abstraction mechanism appropriately, you get at least as good performance as if you had handcoded using lower-level language constructs").
However, we do believe that a program that uses a rule is less error-prone and more maintainable than one that does not.
Often, rules also lead to faster/easier initial development.
As far as we can tell, these rules lead to code that performs as well or better than older, more conventional techniques;
they are meant to follow the zero-overhead principle
("what you don't use, you don't pay for" or "when you use an abstraction mechanism appropriately,
you get at least as good performance as if you had handcoded using lower-level language constructs").
Consider these rules ideals for new code, opportunities to exploit when working on older code, and try to approximate these ideas as closely as feasible. Consider these rules ideals for new code, opportunities to exploit when working on older code, and try to approximate these ideas as closely as feasible.
Remember: Remember:
@@ -170,8 +163,7 @@ that make the use of the most error-prone features of C++ redundant, so that the
The rules emphasize static type safety and resource safety. The rules emphasize static type safety and resource safety.
For that reason, they emphasize possibilities for range checking, for avoiding dereferencing `nullptr`, for avoiding dangling pointers, and the systematic use of exceptions (via RAII). For that reason, they emphasize possibilities for range checking, for avoiding dereferencing `nullptr`, for avoiding dangling pointers, and the systematic use of exceptions (via RAII).
Partly to achieve that and partly to minimize obscure code as a source of errors, Partly to achieve that and partly to minimize obscure code as a source of errors, the rules also emphasize simplicity and the hiding of necessary complexity behind well-specified interfaces.
the rules also emphasize simplicity and the hiding of necessary complexity behind well-specified interfaces.
Many of the rules are prescriptive. Many of the rules are prescriptive.
We are uncomfortable with rules that simply states "don't do that!" without offering an alternative. We are uncomfortable with rules that simply states "don't do that!" without offering an alternative.
@@ -412,7 +404,7 @@ If we wanted both absolute speed and deltas, we would have defined a `Delta` typ
##### Enforcement ##### Enforcement
very hard in general. Very hard in general.
* use `const` consistently (check if member functions modify their object; check if functions modify arguments passed by pointer or reference) * use `const` consistently (check if member functions modify their object; check if functions modify arguments passed by pointer or reference)
* flag uses of casts (casts neuter the type system) * flag uses of casts (casts neuter the type system)
@@ -431,8 +423,7 @@ In such cases, localize the use of necessary extensions and control their use wi
##### Note ##### Note
There are environments where restrictions on use of standard C++ language or library features are necessary, There are environments where restrictions on use of standard C++ language or library features are necessary, e.g., to avoid dynamic memory allocation as required by aircraft control software standards.
e.g., to avoid dynamic memory allocation as required by aircraft control software standards.
In such cases, control their (dis)use with non-core Coding Guidelines. In such cases, control their (dis)use with non-core Coding Guidelines.
##### Enforcement ##### Enforcement
@@ -750,8 +741,7 @@ The date is validated twice (by the `Date` constructor) and passed as a characte
##### Example ##### Example
Excess checking can be costly. Excess checking can be costly.
There are cases where checking early is dumb because you may not ever need the value, There are cases where checking early is dumb because you may not ever need the value, or may only need part of the value that is more easily checked than the whole.
or may only need part of the value that is more easily checked than the whole.
class Jet { // Physics says: e*e < x*x + y*y + z*z class Jet { // Physics says: e*e < x*x + y*y + z*z
float fx, fy, fz, fe; float fx, fy, fz, fe;
@@ -926,7 +916,7 @@ See also
##### Example, bad ##### Example, bad
Controlling the behavior of a function through a global (namespace scope) variable (a call mode) is implicit and potentially confusing. For example, Controlling the behavior of a function through a global (namespace scope) variable (a call mode) is implicit and potentially confusing. For example:
int rnd(double d) int rnd(double d)
{ {
@@ -1040,8 +1030,7 @@ This is one of the most effective solutions to problems related to initializatio
In a multi-threaded environment the initialization of the static object does not introduce a race condition In a multi-threaded environment the initialization of the static object does not introduce a race condition
(unless you carelessly access a shared object from within its constructor). (unless you carelessly access a shared object from within its constructor).
If you, as many do, define a singleton as a class for which only one object is created, functions like `myX` are not singletons, If you, as many do, define a singleton as a class for which only one object is created, functions like `myX` are not singletons, and this useful technique is not an exception to the no-singleton rule.
and this useful technique is not an exception to the no-singleton rule.
##### Enforcement ##### Enforcement
@@ -1057,7 +1046,7 @@ Also, precisely typed code is often optimized better.
##### Example, don't ##### Example, don't
Consider Consider:
void pass(void* data); // void* is suspicious void pass(void* data); // void* is suspicious
@@ -1069,7 +1058,7 @@ Consider using a variant or a pointer to base instead. (Future note: Consider a
##### Example, bad ##### Example, bad
Consider Consider:
void draw_rect(int, int, int, int); // great opportunities for mistakes void draw_rect(int, int, int, int); // great opportunities for mistakes
@@ -1151,7 +1140,7 @@ The function can also be written in such a way that it will accept any time dura
##### Example ##### Example
Consider Consider:
double sqrt(double x); double sqrt(double x);
@@ -1223,7 +1212,7 @@ Preconditions should be part of the interface rather than part of the implementa
##### Example, bad ##### Example, bad
Consider Consider:
int area(int height, int width) { return height*width; } // bad int area(int height, int width) { return height*width; } // bad
@@ -1241,7 +1230,7 @@ Consider using:
##### Example, bad ##### Example, bad
Consider a famous security bug Consider a famous security bug:
void f() // problematic void f() // problematic
{ {
@@ -1387,8 +1376,7 @@ However, if failing to make a connection is considered an error, then a failure
**Exception**: Many traditional interface functions (e.g., UNIX signal handlers) use error codes (e.g., `errno`) to report what are really status codes, rather than errors. You don't have a good alternative to using such, so calling these does not violate the rule. **Exception**: Many traditional interface functions (e.g., UNIX signal handlers) use error codes (e.g., `errno`) to report what are really status codes, rather than errors. You don't have a good alternative to using such, so calling these does not violate the rule.
**Alternative**: If you can't use exceptions (e.g. because your code is full of old-style raw-pointer use or because there are hard-real-time constraints), **Alternative**: If you can't use exceptions (e.g. because your code is full of old-style raw-pointer use or because there are hard-real-time constraints), consider using a style that returns a pair of values:
consider using a style that returns a pair of values:
int val; int val;
int error_code; int error_code;
@@ -1422,7 +1410,7 @@ We don't consider "performance" a valid reason not to use exceptions.
##### Example ##### Example
Consider Consider:
X* compute(args) // don't X* compute(args) // don't
{ {
@@ -1513,7 +1501,7 @@ Note: `length()` is, of course, `std::strlen()` in disguise.
##### Example ##### Example
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)
@@ -1521,13 +1509,15 @@ What if there are fewer than `n` elements in the array pointed to by `q`? Then,
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.
Either is undefined behavior and a potentially very nasty bug. Either is undefined behavior and a potentially very nasty bug.
**Alternative**: Consider using explicit ranges, ##### Alternative
Consider using explicit ranges:
void copy(array_view<const T> r, array_view<T> r2); // copy r to r2 void copy(array_view<const T> r, array_view<T> r2); // copy r to r2
##### Example, bad ##### Example, bad
Consider Consider:
void draw(Shape* p, int n); // poor interface; poor code void draw(Shape* p, int n); // poor interface; poor code
Circle arr[10]; Circle arr[10];
@@ -1609,7 +1599,7 @@ There are functions that are best expressed with four individual arguments, but
##### Example, bad ##### Example, bad
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)
@@ -1625,7 +1615,9 @@ If the order of the parameters is not important, there is no problem:
int max(int a, int b); int max(int a, int b);
**Alternative**: Don't pass arrays as pointers, pass an object representing a range (e.g., an `array_view`): ##### Alternative
Don't pass arrays as pointers, pass an object representing a range (e.g., an `array_view`):
void copy_n(array_view<const T> p, array_view<T> q); // copy from p to q void copy_n(array_view<const T> p, array_view<T> q); // copy from p to q
@@ -1772,8 +1764,7 @@ mess could become hard to understand.
##### Note ##### Note
If you write a non-trivial lambda that potentially can be used in more than one place, If you write a non-trivial lambda that potentially can be used in more than one place, give it a name by assigning it to a (usually non-local) variable.
give it a name by assigning it to a (usually non-local) variable.
##### Example ##### Example
@@ -1806,7 +1797,7 @@ Similarly, lambdas used as callback arguments are sometimes non-trivial, yet unl
##### Example ##### Example
Consider Consider:
void read_and_print() // bad void read_and_print() // bad
{ {
@@ -1867,7 +1858,7 @@ Functions with complex control structures are more likely to be long and more li
##### Example ##### Example
Consider Consider:
double simpleFunc(double val, int flag1, int flag2) double simpleFunc(double val, int flag1, int flag2)
// simpleFunc: takes a value and calculates the expected ASIC output, given the two mode flags. // simpleFunc: takes a value and calculates the expected ASIC output, given the two mode flags.
@@ -2059,8 +2050,7 @@ Unless the program is crafted to survive memory exhaustion, that may be just the
##### Note ##### Note
In most programs, most functions can throw In most programs, most functions can throw
(e.g., because they use `new`, call functions that do, or use library functions that reports failure by throwing), (e.g., because they use `new`, call functions that do, or use library functions that reports failure by throwing), so don't just sprinkle `noexcept` all over the place.
so don't just sprinkle `noexcept` all over the place.
`noexcept` is most useful for frequently used, low-level functions. `noexcept` is most useful for frequently used, low-level functions.
##### Note ##### Note
@@ -2124,8 +2114,7 @@ There are a variety of ways to pass arguments to a function and to return values
##### Reason ##### Reason
Using "unusual and clever" techniques causes surprises, slows understanding by other programmers, and encourages bugs. Using "unusual and clever" techniques causes surprises, slows understanding by other programmers, and encourages bugs.
If you really feel the need for an optimization beyond the common techniques, measure to ensure that it really is an improvement, If you really feel the need for an optimization beyond the common techniques, measure to ensure that it really is an improvement, and document/comment because the improvement may not be portable.
and document/comment because the improvement may not be portable.
![Normal parameter passing table](./param-passing-normal.png "Normal parameter passing") ![Normal parameter passing table](./param-passing-normal.png "Normal parameter passing")
@@ -2199,14 +2188,13 @@ The (optional) return value optimization doesn't handle the assignment case.
##### Enforcement ##### Enforcement
This is a philosophical guideline that is infeasible to check directly and completely. This is a philosophical guideline that is infeasible to check directly and completely.
However, many of the detailed rules (F.16-F.45) can be checked, However, many of the detailed rules (F.16-F.45) can be checked, such as passing a `const int&`, returning an `array<BigPOD>` by value, and returning a pointer to free store alloced by the function.
such as passing a `const int&`, returning an `array<BigPOD>` by value, and returning a pointer to free store alloced by the function.
### <a name="Rf-ptr"></a> F.16: Use `T*` or `owner<T*>` to designate a single object ### <a name="Rf-ptr"></a> F.16: Use `T*` or `owner<T*>` to designate a single object
##### Reason ##### Reason
In traditional C and C++ code, plain `T*` is used for many weakly-related purposes, such as In traditional C and C++ code, plain `T*` is used for many weakly-related purposes, such as:
* Identify a (single) object (not to be deleted by this function) * Identify a (single) object (not to be deleted by this function)
* Point to an object allocated on the free store (and delete it later) * Point to an object allocated on the free store (and delete it later)
@@ -2220,7 +2208,7 @@ Additionally, when debugging, `owner<T*>` and `not_null<T>` can be instrumented
##### Example ##### Example
Consider Consider:
int length(Record* p); int length(Record* p);
@@ -2277,7 +2265,7 @@ A `not_null<T*>` is assumed not to be the `nullptr`; a `T*` may be the `nullptr`
##### Reason ##### Reason
Informal/non-explicit ranges are a source of errors Informal/non-explicit ranges are a source of errors.
##### Example ##### Example
@@ -2314,7 +2302,7 @@ We must distinguish C-style strings from a pointer to a single character or an o
##### Example ##### Example
Consider Consider:
int length(const char* p); int length(const char* p);
@@ -2401,8 +2389,7 @@ Thus `T&` could be and in-out-parameter. That can in itself be a problem and a s
// ... // ...
} }
Here, the writer of `g()` is supplying a buffer for `f()` to fill, Here, the writer of `g()` is supplying a buffer for `f()` to fill, but `f()` simply replaces it (at a somewhat higher cost than a simple copy of the characters).
but `f()` simply replaces it (at a somewhat higher cost than a simple copy of the characters).
If the writer of `g()` makes an assumption about the size of `buffer` a bad logic error can happen. If the writer of `g()` makes an assumption about the size of `buffer` a bad logic error can happen.
##### Enforcement ##### Enforcement
@@ -2591,8 +2578,7 @@ With C++11 we can write this, putting the results directly in existing local var
##### Note ##### Note
In some cases it may be useful to return a specific, user-defined `Value_or_error` type along the lines of `variant<T, error_code>`, In some cases it may be useful to return a specific, user-defined `Value_or_error` type along the lines of `variant<T, error_code>`, rather than using the generic `tuple`.
rather than using the generic `tuple`.
##### Enforcement ##### Enforcement
@@ -2686,7 +2672,7 @@ After the return from a function its local objects no longer exist:
} }
Here on one popular implementation I got the output Here on one popular implementation I got the output:
*p == 999 *p == 999
gx == 999 gx == 999
@@ -2738,8 +2724,7 @@ The pointer stored in `glob` could be used much later and cause trouble in unpre
##### Note ##### Note
The address of a local variable can be "returned"/leaked by a return statement, The address of a local variable can be "returned"/leaked by a return statement, by a `T&` out-parameter, as a member of a returned object, as an element of a returned array, and more.
by a `T&` out-parameter, as a member of a returned object, as an element of a returned array, and more.
##### Note ##### Note
@@ -2970,7 +2955,7 @@ An invariant is a logical condition for the members of an object that a construc
int volume; int volume;
}; };
but but:
class Date { class Date {
private: private:
@@ -3010,9 +2995,7 @@ For example, we can now change the representation of a `Date` without affecting
##### Note ##### Note
Using a class in this way to represent the distinction between interface and implementation is of course not the only way. Using a class in this way to represent the distinction between interface and implementation is of course not the only way.
For example, we can use a set of declarations of freestanding functions in a namespace, For example, we can use a set of declarations of freestanding functions in a namespace, an abstract base class, or a template function with concepts to represent an interface.
an abstract base class,
or a template function with concepts to represent an interface.
The most important issue is to explicitly distinguish between an interface and its implementation "details." The most important issue is to explicitly distinguish between an interface and its implementation "details."
Ideally, and typically, an interface is far more stable than its implementation(s). Ideally, and typically, an interface is far more stable than its implementation(s).
@@ -3051,8 +3034,7 @@ The snag is that many member functions that do not need to touch data members di
##### Reason ##### Reason
A helper function is a function (usually supplied by the writer of a class) that does not need direct access to the representation of the class, A helper function is a function (usually supplied by the writer of a class) that does not need direct access to the representation of the class, yet is seen as part of the useful interface to the class.
yet is seen as part of the useful interface to the class.
Placing them in the same namespace as the class makes their relationship to the class obvious and allows them to be found by argument dependent lookup. Placing them in the same namespace as the class makes their relationship to the class obvious and allows them to be found by argument dependent lookup.
##### Example ##### Example
@@ -3577,8 +3559,7 @@ The default copy operation will just copy the `p1.p` into `p2.p` leading to a do
##### Note ##### Note
Often the simplest way to get a destructor is to replace the pointer with a smart pointer (e.g., `std::unique_ptr`) Often the simplest way to get a destructor is to replace the pointer with a smart pointer (e.g., `std::unique_ptr`) and let the compiler arrange for proper destruction to be done implicitly.
and let the compiler arrange for proper destruction to be done implicitly.
##### Note ##### Note
@@ -3939,8 +3920,7 @@ For a variable definition (e.g., on the stack or as a member of another object)
##### Reason ##### Reason
Many language and library facilities rely on default constructors, Many language and library facilities rely on default constructors, e.g. `T a[10]` and `std::vector<T> v(10)` default initializes their elements.
e.g. `T a[10]` and `std::vector<T> v(10)` default initializes their elements.
##### Example ##### Example
@@ -4180,8 +4160,7 @@ How would a maintainer know whether `j` was deliberately uninitialized (probably
##### Reason ##### Reason
If the state of a base class object must depend on the state of a derived part of the object, If the state of a base class object must depend on the state of a derived part of the object, we need to use a virtual function (or equivalent) while minimizing the window of opportunity to misuse an imperfectly constructed object.
we need to use a virtual function (or equivalent) while minimizing the window of opportunity to misuse an imperfectly constructed object.
##### Example, bad ##### Example, bad
@@ -4241,7 +4220,7 @@ Conventional factory functions allocate on the free store, rather than on the st
##### Reason ##### Reason
To avoid repetition and accidental differences To avoid repetition and accidental differences.
##### Example, bad ##### Example, bad
@@ -5713,7 +5692,7 @@ Flag member operator functions.
##### Example ##### Example
Consider Consider:
void print(int a); void print(int a);
void print(int a, int base); void print(int a, int base);
@@ -5739,7 +5718,7 @@ These three functions all prints their arguments (appropriately). Adding to the
##### Example ##### Example
Consider Consider:
void open_gate(Gate& g); // remove obstacle from garage exit lane void open_gate(Gate& g); // remove obstacle from garage exit lane
void fopen(const char*name, const char* mode); // open file void fopen(const char*name, const char* mode); // open file
@@ -5803,7 +5782,7 @@ Flag all conversion operators.
##### Reason ##### Reason
You can overload by defining two different lambdas with the same name You can overload by defining two different lambdas with the same name.
##### Example ##### Example
@@ -5926,7 +5905,7 @@ Enumeration rule summary:
##### Reason ##### Reason
to minimize surprises To minimize surprises.
##### Example ##### Example
@@ -5940,7 +5919,7 @@ Enumeration rule summary:
##### Reason ##### Reason
Convenience of us and avoidance of errors. Convenience of use and avoidance of errors.
##### Example ##### Example
@@ -5954,7 +5933,7 @@ Enumeration rule summary:
##### Reason ##### Reason
Avoid clashes with macros Avoid clashes with macros.
##### Example ##### Example
@@ -5987,8 +5966,7 @@ The fundamental aim is to ensure that we don't leak any resources and that we do
An entity that is responsible for releasing a resource is called an owner. An entity that is responsible for releasing a resource is called an owner.
There are a few cases where leaks can be acceptable or even optimal: There are a few cases where leaks can be acceptable or even optimal:
if you are writing a program that simply produces an output based on an input and the amount of memory needed is proportional to the size of the input, If you are writing a program that simply produces an output based on an input and the amount of memory needed is proportional to the size of the input, the optimal strategy (for performance and ease of programming) is sometimes simply never to delete anything.
the optimal strategy (for performance and ease of programming) is sometimes simply never to delete anything.
If you have enough memory to handle your largest input, leak away, but be sure to give a good error message if you are wrong. If you have enough memory to handle your largest input, leak away, but be sure to give a good error message if you are wrong.
Here, we ignore such cases. Here, we ignore such cases.
@@ -6032,12 +6010,11 @@ Here, we ignore such cases.
To avoid leaks and the complexity of manual resource management. To avoid leaks and the complexity of manual resource management.
C++'s language-enforced constructor/destructor symmetry mirrors the symmetry inherent in resource acquire/release function pairs such as `fopen`/`fclose`, `lock`/`unlock`, and `new`/`delete`. C++'s language-enforced constructor/destructor symmetry mirrors the symmetry inherent in resource acquire/release function pairs such as `fopen`/`fclose`, `lock`/`unlock`, and `new`/`delete`.
Whenever you deal with a resource that needs paired acquire/release function calls, Whenever you deal with a resource that needs paired acquire/release function calls, encapsulate that resource in an object that enforces pairing for you -- acquire the resource in its constructor, and release it in its destructor.
encapsulate that resource in an object that enforces pairing for you -- acquire the resource in its constructor, and release it in its destructor.
##### Example, bad ##### Example, bad
Consider Consider:
void send(X* x, cstring_view destination) { void send(X* x, cstring_view destination) {
auto port = OpenPort(destination); auto port = OpenPort(destination);
@@ -6055,7 +6032,7 @@ Further, if any of the code marked `...` throws an exception, then `x` is leaked
##### Example ##### Example
Consider Consider:
void send(unique_ptr<X> x, cstring_view destination) { // x owns the X void send(unique_ptr<X> x, cstring_view destination) { // x owns the X
Port port{destination}; // port owns the PortHandle Port port{destination}; // port owns the PortHandle
@@ -6196,9 +6173,7 @@ Returning a (raw) pointer imposes a life-time management burden on the caller; t
delete p; delete p;
} }
In addition to suffering from then problem from [leak](#???), this adds a spurious allocation and deallocation operation, In addition to suffering from then problem from [leak](#???), this adds a spurious allocation and deallocation operation, and is needlessly verbose. If Gadget is cheap to move out of a function (i.e., is small or has an efficient move operation), just return it "by value:'
and is needlessly verbose. If Gadget is cheap to move out of a function (i.e., is small or has an efficient move operation),
just return it "by value:'
Gadget make_gadget(int n) Gadget make_gadget(int n)
{ {
@@ -6213,8 +6188,7 @@ This rule applies to factory functions.
##### Note ##### Note
If pointer semantics is required (e.g., because the return type needs to refer to a base class of a class hierarchy (an interface)), If pointer semantics is required (e.g., because the return type needs to refer to a base class of a class hierarchy (an interface)), return a "smart pointer."
return a "smart pointer."
##### Enforcement ##### Enforcement
@@ -6398,8 +6372,7 @@ The use of the file handle (in `ifstream`) is simple, efficient, and safe.
##### Reason ##### Reason
If you perform two explicit resource allocations in one statement, If you perform two explicit resource allocations in one statement, you could leak resources because the order of evaluation of many subexpressions, including function arguments, is unspecified.
you could leak resources because the order of evaluation of many subexpressions, including function arguments, is unspecified.
##### Example ##### Example
@@ -6480,7 +6453,7 @@ Flag incomplete pairs.
##### Example ##### Example
Consider Consider:
void f() void f()
{ {
@@ -6500,11 +6473,11 @@ This will leak the object used to initialize `p1` (only).
##### Reason ##### Reason
a `unique_ptr` is conceptually simpler and more predictable (you know when destruction happens) and faster (you don't implicitly maintain a use count). A `unique_ptr` is conceptually simpler and more predictable (you know when destruction happens) and faster (you don't implicitly maintain a use count).
##### Example, bad ##### Example, bad
This needlessly adds and maintains a reference count This needlessly adds and maintains a reference count.
void f() void f()
{ {
@@ -6514,7 +6487,7 @@ This will leak the object used to initialize `p1` (only).
##### Example ##### Example
This is more efficient This is more efficient:
void f() void f()
{ {
@@ -6534,7 +6507,7 @@ This is more efficient
##### Example ##### Example
Consider Consider:
shared_ptr<X> p1 { new X{2} }; // bad shared_ptr<X> p1 { new X{2} }; // bad
auto p = make_shared<X>(2); // good auto p = make_shared<X>(2); // good
@@ -6549,7 +6522,7 @@ The `make_shared()` version mentions `X` only once, so it is usually shorter (as
##### Reason ##### Reason
for convenience and consistency with `shared_ptr`. For convenience and consistency with `shared_ptr`.
##### Note ##### Note
@@ -6654,8 +6627,7 @@ Any type (including primary template or specialization) that overloads unary `*`
Both cases are an error under the [`sharedptrparam` guideline](#Rr-smartptrparam): Both cases are an error under the [`sharedptrparam` guideline](#Rr-smartptrparam):
`p` is a `Shared_ptr`, but nothing about its sharedness is used here and passing it by value is a silent pessimization; `p` is a `Shared_ptr`, but nothing about its sharedness is used here and passing it by value is a silent pessimization;
these functions should accept a smart pointer only if they need to participate in the widget's lifetime management. Otherwise they should accept a `widget*`, if it can be `nullptr`. Otherwise, and ideally, the function should accept a `widget&`. these functions should accept a smart pointer only if they need to participate in the widget's lifetime management. Otherwise they should accept a `widget*`, if it can be `nullptr`. Otherwise, and ideally, the function should accept a `widget&`.
These smart pointers match the `Shared_ptr` concept, These smart pointers match the `Shared_ptr` concept, so these guideline enforcement rules work on them out of the box and expose this common pessimization.
so these guideline enforcement rules work on them out of the box and expose this common pessimization.
### <a name="Rr-uniqueptrparam"></a> R.32: Take a `unique_ptr<widget>` parameter to express that a function assumes ownership of a `widget` ### <a name="Rr-uniqueptrparam"></a> R.32: Take a `unique_ptr<widget>` parameter to express that a function assumes ownership of a `widget`
@@ -6903,11 +6875,11 @@ It is available as part of all C++ Implementations.
auto sum = accumulate(begin(a), end(a), 0.0); // good auto sum = accumulate(begin(a), end(a), 0.0); // good
a range version of `accumulate` would be even better a range version of `accumulate` would be even better:
auto sum = accumulate(v, 0.0); // better auto sum = accumulate(v, 0.0); // better
but don't hand-code a well-known algorithm but don't hand-code a well-known algorithm:
int max = v.size(); // bad: verbose, purpose unstated int max = v.size(); // bad: verbose, purpose unstated
double sum = 0.0; double sum = 0.0;
@@ -7171,7 +7143,7 @@ Flag all uses of ALL CAPS. For older code, accept ALL CAPS for macro names and f
##### Reason ##### Reason
One-declaration-per line increases readability and avoid mistake related to the C/C++ grammar. It leaves room for a `//`-comment One-declaration-per line increases readability and avoid mistake related to the C/C++ grammar. It leaves room for a `//`-comment.
##### Example, bad ##### Example, bad
@@ -7184,7 +7156,7 @@ Flag all uses of ALL CAPS. For older code, accept ALL CAPS for macro names and f
template <class InputIterator, class Predicate> template <class InputIterator, class Predicate>
bool any_of(InputIterator first, InputIterator last, Predicate pred); bool any_of(InputIterator first, InputIterator last, Predicate pred);
or better using concepts or better using concepts:
bool any_of(InputIterator first, InputIterator last, Predicate pred); bool any_of(InputIterator first, InputIterator last, Predicate pred);
@@ -7192,14 +7164,14 @@ or better using concepts
double scalbn(double x, int n); // OK: x*pow(FLT_RADIX, n); FLT_RADIX is usually 2 double scalbn(double x, int n); // OK: x*pow(FLT_RADIX, n); FLT_RADIX is usually 2
or or:
double scalbn( // better: x*pow(FLT_RADIX, n); FLT_RADIX is usually 2 double scalbn( // better: x*pow(FLT_RADIX, n); FLT_RADIX is usually 2
double x, // base value double x, // base value
int n // exponent int n // exponent
); );
or or:
double scalbn(double base, int exponent); // better: base*pow(FLT_RADIX, exponent); FLT_RADIX is usually 2 double scalbn(double base, int exponent); // better: base*pow(FLT_RADIX, exponent); FLT_RADIX is usually 2
@@ -7217,7 +7189,7 @@ Flag non-function arguments with multiple declarators involving declarator opera
##### Example ##### Example
Consider Consider:
auto p = v.begin(); // vector<int>::iterator auto p = v.begin(); // vector<int>::iterator
auto s = v.size(); auto s = v.size();
@@ -7329,7 +7301,7 @@ Sometimes, a lambda can be used as an initializer to avoid an uninitialized vari
return p.second; return p.second;
}; };
or maybe or maybe:
Value v = []() { Value v = []() {
auto p = get_value(); // get_value() returns a pair<error_code, Value> auto p = get_value(); // get_value() returns a pair<error_code, Value>
@@ -7739,7 +7711,7 @@ Statements control the flow of control (except for function calls and exception
} }
} }
rather than rather than:
void use2(int n) void use2(int n)
{ {
@@ -8066,15 +8038,14 @@ Tricky. How complicated must an expression be to be considered complicated? Writ
if (a && b==1) // OK? if (a && b==1) // OK?
if (a & b==1) // OK? if (a & b==1) // OK?
Note: We recommend that programmers know their precedence table for the arithmetic operations, the logical operations, Note: We recommend that programmers know their precedence table for the arithmetic operations, the logical operations, but consider mixing bitwise logical operations with other operators in need of parentheses.
but consider mixing bitwise logical operations with other operators in need of parentheses.
if (a && b==1) // OK: means a&&(b==1) if (a && b==1) // OK: means a&&(b==1)
if (a & b==1) // bad: means (a&b)==1 if (a & b==1) // bad: means (a&b)==1
##### Note ##### Note
You should know enough not to need parentheses for You should know enough not to need parentheses for:
if (a<0 || a<=max) { if (a<0 || a<=max) {
// ... // ...
@@ -8133,7 +8104,7 @@ Can be detected by a good analyzer.
##### Reason ##### Reason
that order is unspecified Because that order is unspecified.
##### Example ##### Example
@@ -8233,7 +8204,7 @@ A good analyzer can detect all narrowing conversions. However, flagging all narr
##### Example ##### Example
Consider Consider:
void f(int); void f(int);
void f(char*); void f(char*);
@@ -8311,7 +8282,7 @@ Flag C-style and functional casts.
##### Reason ##### Reason
It makes a lie out of `const` It makes a lie out of `const`.
##### Note ##### Note
@@ -8624,7 +8595,7 @@ If your program spends most of its time waiting for the web or for a human, opti
##### Reason ##### Reason
Low-level code sometimes inhibits optimizations. Optimizers sometimes do marvels with high-level code Low-level code sometimes inhibits optimizations. Optimizers sometimes do marvels with high-level code.
##### Note ##### Note
@@ -8656,8 +8627,7 @@ Often, you will be surprised.
##### Reason ##### Reason
Type violations, weak types (e.g. `void*`s), and low level code (e.g., manipulation of sequences as individual bytes) Type violations, weak types (e.g. `void*`s), and low level code (e.g., manipulation of sequences as individual bytes) make the job of the optimizer much harder. Simple code often optimizes better than hand-crafted complex code.
make the job of the optimizer much harder. Simple code often optimizes better than hand-crafted complex code.
??? ???
@@ -8786,8 +8756,7 @@ Concurrency rule summary:
Speaking of concurrency, should there be a note about the dangers of `std::atomic` (weapons)? Speaking of concurrency, should there be a note about the dangers of `std::atomic` (weapons)?
A lot of people, myself included, like to experiment with `std::memory_order`, but it is perhaps best to keep a close watch on those things in production code. A lot of people, myself included, like to experiment with `std::memory_order`, but it is perhaps best to keep a close watch on those things in production code.
Even vendors mess this up: Microsoft had to fix their `shared_ptr` (weak refcount decrement wasn't synchronized-with the destructor, if I recall correctly, although it was only a problem on ARM, not Intel) Even vendors mess this up: Microsoft had to fix their `shared_ptr` (weak refcount decrement wasn't synchronized-with the destructor, if I recall correctly, although it was only a problem on ARM, not Intel)
and everyone (gcc, clang, Microsoft, and intel) had to fix their `compare_exchange_*` this year, and everyone (gcc, clang, Microsoft, and intel) had to fix their `compare_exchange_*` this year, after an implementation bug caused losses to some finance company and they were kind enough to let the community know.
after an implementation bug caused losses to some finance company and they were kind enough to let the community know.
It should definitely mention that `volatile` does not provide atomicity, does not synchronize between threads, and does not prevent instruction reordering (neither compiler nor hardware), and simply has nothing to do with concurrency. It should definitely mention that `volatile` does not provide atomicity, does not synchronize between threads, and does not prevent instruction reordering (neither compiler nor hardware), and simply has nothing to do with concurrency.
@@ -8881,7 +8850,7 @@ Error-handling rule summary:
##### Reason ##### Reason
a consistent and complete strategy for handling errors and resource leaks is hard to retrofit into a system. A consistent and complete strategy for handling errors and resource leaks is hard to retrofit into a system.
### <a name="Re-throw"></a> E.2: Throw an exception to signal that a function can't perform its assigned task ### <a name="Re-throw"></a> E.2: Throw an exception to signal that a function can't perform its assigned task
@@ -8903,14 +8872,13 @@ Error-handling rule summary:
// ... // ...
} }
Here, `vector` and `string`s constructors may not be able to allocate sufficient memory for their elements, Here, `vector` and `string`s constructors may not be able to allocate sufficient memory for their elements, `vector`s constructor may not be able copy the `Thing`s in its initializer list, and `File_handle` may not be able to open the required file.
`vector`s constructor may not be able copy the `Thing`s in its initializer list, and `File_handle` may not be able to open the required file.
In each case, they throw an exception for `use()`'s caller to handle. In each case, they throw an exception for `use()`'s caller to handle.
If `use()` could handle the failure to construct `bar` it can take control using `try`/`catch`. If `use()` could handle the failure to construct `bar` it can take control using `try`/`catch`.
In either case, `Foo`'s constructor correctly destroys constructed members before passing control to whatever tried to create a `Foo`. In either case, `Foo`'s constructor correctly destroys constructed members before passing control to whatever tried to create a `Foo`.
Note that there is no return value that could contain an error code. Note that there is no return value that could contain an error code.
The `File_handle` constructor might defined like this The `File_handle` constructor might defined like this:
File_handle::File_handle(const string& name, const string& mode) File_handle::File_handle(const string& name, const string& mode)
:f{fopen(name.c_str(), mode.c_str())} :f{fopen(name.c_str(), mode.c_str())}
@@ -8970,8 +8938,7 @@ There is nothing exceptional about finding a value in a `vector`.
##### Reason ##### Reason
To use an objects it must be in a valid state (defined formally or informally by an invariant) To use an objects it must be in a valid state (defined formally or informally by an invariant) and to recover from an error every object not destroyed must be in a valid state.
and to recover from an error every object not destroyed must be in a valid state.
##### Note ##### Note
@@ -9010,7 +8977,7 @@ Not all member function can be called.
// ... // ...
} }
We could carefully release the resource before the throw We could carefully release the resource before the throw:
void f2(int i) // Clumsy: explicit release void f2(int i) // Clumsy: explicit release
{ {
@@ -9069,8 +9036,7 @@ We know of only a few good reasons:
(in particular without a recognizable ownership strategy) so that exceptions could cause leaks. (in particular without a recognizable ownership strategy) so that exceptions could cause leaks.
* We get fired if we challenge our manager's ancient wisdom. * We get fired if we challenge our manager's ancient wisdom.
Only the first of these reasons is fundamental, Only the first of these reasons is fundamental, so whenever possible, use exception to implement RAII.
so whenever possible, use exception to implement RAII.
When exceptions cannot be used, simulate RAII. When exceptions cannot be used, simulate RAII.
That is, systematically check that objects are valid after construction and still release all resources in the destructor. That is, systematically check that objects are valid after construction and still release all resources in the destructor.
One strategy is to add a `valid()` operation to every resource handle: One strategy is to add a `valid()` operation to every resource handle:
@@ -9090,9 +9056,7 @@ One strategy is to add a `valid()` operation to every resource handle:
// ... // ...
} // destructors clean up as usual } // destructors clean up as usual
Obviously, this increases the size of the code, Obviously, this increases the size of the code, doesn't allow for implicit propagation of "exceptions" (`valid()` checks), and `valid()` checks can be forgotten.
doesn't allow for implicit propagation of "exceptions" (`valid()` checks),
and `valid()` checks can be forgotten.
Prefer to use exceptions. Prefer to use exceptions.
**See also**: [discussion](#Sd-noexcept). **See also**: [discussion](#Sd-noexcept).
@@ -9271,7 +9235,7 @@ Catch `throw` and `catch` of a built-in type. Maybe warn about `throw` and `catc
// ... // ...
} }
Instead, use Instead, use:
catch (exception& e) { /* ... */ } catch (exception& e) { /* ... */ }
@@ -9614,8 +9578,7 @@ For additional generality and reusability, we could also use a more general `Con
##### Note ##### Note
If we define a template to require exactly the operations required for a single implementation of a single algorithm If we define a template to require exactly the operations required for a single implementation of a single algorithm
(e.g., requiring just `+=` rather than also `=` and `+`) and only those, (e.g., requiring just `+=` rather than also `=` and `+`) and only those, we have overconstrained maintainers.
we have overconstrained maintainers.
We aim to minimize requirements on template arguments, but the absolutely minimal requirements of an implementation is rarely a meaningful concept. We aim to minimize requirements on template arguments, but the absolutely minimal requirements of an implementation is rarely a meaningful concept.
##### Note ##### Note
@@ -9690,8 +9653,7 @@ This doesn't directly express the intent of the programmer and hides the structu
Hiding the `void*` behind macros simply obscures the problems and introduces new opportunities for confusion. Hiding the `void*` behind macros simply obscures the problems and introduces new opportunities for confusion.
**Exceptions**: If you need an ABI-stable interface, **Exceptions**: If you need an ABI-stable interface, you might have to provide a base implementation and express the (type-safe) template in terms of that.
you might have to provide a base implementation and express the (type-safe) template in terms of that.
See [Stable base](#Rt-abi). See [Stable base](#Rt-abi).
##### Enforcement ##### Enforcement
@@ -9789,7 +9751,7 @@ Specifying concepts for template arguments is a powerful design tool.
// ... // ...
} }
or equivalently and more succinctly or equivalently and more succinctly:
template<Input_iterator Iter, typename Val> template<Input_iterator Iter, typename Val>
requires Equality_comparable<Value_type<Iter>, Val> requires Equality_comparable<Value_type<Iter>, Val>
@@ -9935,7 +9897,7 @@ and should be used only as building blocks for meaningful concepts, rather than
auto zz = plus(xx, yy); // zz = "79" auto zz = plus(xx, yy); // zz = "79"
Maybe the concatenation was expected. More likely, it was an accident. Defining minus equivalently would give dramatically different sets of accepted types. Maybe the concatenation was expected. More likely, it was an accident. Defining minus equivalently would give dramatically different sets of accepted types.
This `Addable` violates the mathematical rule that addition is supposed to be commutative: `a+b == b+a`, This `Addable` violates the mathematical rule that addition is supposed to be commutative: `a+b == b+a`.
##### Note ##### Note
@@ -10388,8 +10350,7 @@ This rule should not be necessary; the committee cannot agree on how to fix ADL,
##### Note ##### Note
Having a template operate only on its arguments would be one way of reducing the number of dependencies to a minimum, Having a template operate only on its arguments would be one way of reducing the number of dependencies to a minimum, but that would generally be unmanageable. For example, an algorithm usually uses other algorithms.
but that would generally be unmanageable. For example, an algorithm usually uses other algorithms.
##### Enforcement ##### Enforcement
@@ -10621,8 +10582,7 @@ The two language mechanisms can be use effectively in combination, but a few des
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, 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.
but it is not unheard of and it makes a good example of what not to do.
Given this, the compiler cannot know if `vector<int>::sort()` is called, so it must generate code for it. Given this, the compiler cannot know if `vector<int>::sort()` is called, so it must generate code for it.
Similar for `vector<string>::sort()`. Similar for `vector<string>::sort()`.
@@ -11366,8 +11326,7 @@ The errors will not be caught until link time for a program calling `bar` or `fo
double foobar(int); // error: wrong return type double foobar(int); // error: wrong return type
The return-type error for `foobar` is now caught immediately when `foo.cpp` is compiled. The return-type error for `foobar` is now caught immediately when `foo.cpp` is compiled.
The argument-type error for `bar` cannot be caught until link time because of the possibility of overloading, The argument-type error for `bar` cannot be caught until link time because of the possibility of overloading, but systematic use of `.h` files increases the likelihood that it is caught earlier by the programmer.
but systematic use of `.h` files increases the likelihood that it is caught earlier by the programmer.
##### Enforcement ##### Enforcement
@@ -11417,7 +11376,7 @@ Doing so takes away an `#include`r's ability to effectively disambiguate and to
##### Enforcement ##### Enforcement
Flag `.h` files without `#include` guards Flag `.h` files without `#include` guards.
### <a name="Rs-cycles"></a> SF.9: Avoid cyclic dependencies among source files ### <a name="Rs-cycles"></a> SF.9: Avoid cyclic dependencies among source files
@@ -12231,8 +12190,7 @@ There is no really good way to say "pointer to a single `char` (`string_view{p,
* `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, 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.
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`.
French accent optional. French accent optional.
@@ -12443,7 +12401,7 @@ ISO Standard, use lower case only and digits, separate words with underscores:
* `vector` * `vector`
* `my_map` * `my_map`
Avoid double underscores `__` Avoid double underscores `__`.
##### Example ##### Example
@@ -12456,7 +12414,7 @@ ISO Standard, but with upper case used for your own types and concepts:
##### Example ##### Example
CamelCase: capitalize each word in a multi-word identifier CamelCase: capitalize each word in a multi-word identifier:
* `int` * `int`
* `vector` * `vector`
@@ -12480,7 +12438,7 @@ Would be possible except for the use of libraries with varying conventions.
##### Reason ##### Reason
To avoid confusing macros from names that obeys scope and type rules To avoid confusing macros from names that obeys scope and type rules.
##### Example ##### Example
@@ -12488,7 +12446,7 @@ Would be possible except for the use of libraries with varying conventions.
##### Note ##### Note
This rule applies to non-macro symbolic constants This rule applies to non-macro symbolic constants:
enum bad { BAD, WORSE, HORRIBLE }; // BAD enum bad { BAD, WORSE, HORRIBLE }; // BAD
@@ -13315,7 +13273,7 @@ In general, a tool cannot know if a class is a resource handle. However, if a cl
##### Enforcement ##### Enforcement
When is a class a container? When is a class a container? ???
# <a name="S-unclassified"></a> To-do: Unclassified proto-rules # <a name="S-unclassified"></a> To-do: Unclassified proto-rules
@@ -13344,7 +13302,7 @@ Alternatively, we will decide that no change is needed and delete the entry.
* Speaking of lambdas, what would weigh in on the decision between lambdas and (local?) classes in algorithm calls and other callback scenarios? * Speaking of lambdas, what would weigh in on the decision between lambdas and (local?) classes in algorithm calls and other callback scenarios?
* And speaking of `std::bind`, Stephen T. Lavavej criticizes it so much I'm starting to wonder if it is indeed going to fade away in future. Should lambdas be recommended instead? * And speaking of `std::bind`, Stephen T. Lavavej criticizes it so much I'm starting to wonder if it is indeed going to fade away in future. Should lambdas be recommended instead?
* What to do with leaks out of temporaries? : `p = (s1+s2).c_str();` * What to do with leaks out of temporaries? : `p = (s1+s2).c_str();`
* pointer/iterator invalidation leading to dangling pointers * pointer/iterator invalidation leading to dangling pointers:
void bad() void bad()
{ {