@ -187,7 +187,7 @@ You can look at design concepts used to express the rules:
This document is a set of guidelines for using C++ well.
The aim of this document is to help people to use modern C++ effectively.
By "modern C++" we mean effective use of the ISO C++ standard (currently C++17, but almost all of our recommendations also apply to C++14 and C++11).
By "modern C++" we mean effective use of the ISO C++ standard (currently C++20, but almost all of our recommendations also apply to C++17, C++14 and C++11).
In other words, what would you like your code to look like in 5 years' time, given that you can start now? In 10 years' time?
The guidelines are focused on relatively high-level issues, such as interfaces, resource management, memory management, and concurrency.
@ -224,7 +224,7 @@ We plan to modify and extend this document as our understanding improves and the
# <aname="S-introduction"></a>In: Introduction
This is a set of core guidelines for modern C++ (currently C++17) taking likely future enhancements and ISO Technical Specifications (TSs) into account.
This is a set of core guidelines for modern C++ (currently C++20 and C++17) taking likely future enhancements and ISO Technical Specifications (TSs) into account.
The aim is to help C++ programmers to write simpler, more efficient, more maintainable code.
Introduction summary:
@ -594,7 +594,7 @@ In such cases, control their (dis)use with an extension of these Coding Guidelin
##### Enforcement
Use an up-to-date C++ compiler (currently C++17, C++14, or C++11) with a set of options that do not accept extensions.
Use an up-to-date C++ compiler (currently C++20 or C++17) with a set of options that do not accept extensions.
### <aname="Rp-what"></a>P.3: Express intent
@ -1432,7 +1432,7 @@ Consider:
Callers are unsure what types are allowed and if the data may
be mutated as `const` is not specified. Note all pointer types
implicitly convert to void*, so it is easy for callers to provide this value.
implicitly convert to `void*`, so it is easy for callers to provide this value.
The callee must `static_cast` data to an unverified type to use it.
That is error-prone and verbose.
@ -1479,7 +1479,7 @@ This design is more explicit, safe and legible:
s.frequency = alarm_settings::every_10_seconds;
set_settings(s);
For the case of a set of boolean values consider using a flags enum; a pattern that expresses a set of boolean values.
For the case of a set of boolean values consider using a flags `enum`; a pattern that expresses a set of boolean values.
Soon (in C++20), all compilers will be able to check `requires` clauses once the `//` is removed.
Concepts are supported in GCC 6.1 and later.
**See also**: [Generic programming](#SS-GP) and [concepts](#SS-concepts).
##### Enforcement
(Not yet enforceable) A language facility is under specification. When the language facility is available, warn if any non-variadic template parameter is not constrained by a concept (in its declaration or mentioned in a `requires` clause).
Warn if any non-variadic template parameter is not constrained by a concept (in its declaration or mentioned in a `requires` clause).
### <aname="Ri-except"></a>I.10: Use exceptions to signal a failure to perform a required task
@ -2077,10 +2072,11 @@ To really reduce the number of arguments, we need to bundle the arguments into h
Grouping arguments into "bundles" is a general technique to reduce the number of arguments and to increase the opportunities for checking.
Alternatively, we could use concepts (as defined by the ISO TS) to define the notion of three types that must be usable for merging:
Alternatively, we could use a standard library concept to define the notion of three types that must be usable for merging:
Mergeable{In1, In2, Out}
OutputIterator merge(In1 r1, In2 r2, Out result);
template<classIn1,classIn2,classOut>
requires mergeable<In1,In2,Out>
Out merge(In1 r1, In2 r2, Out result);
##### Example
@ -2820,10 +2816,10 @@ We can catch many common cases of dangling pointers statically (see [lifetime sa
* Flag a parameter of a smart pointer type (a type that overloads `operator->` or `operator*`) that is copyable/movable but never copied/moved from in the function body, and that is never modified, and that is not passed along to another function that could do so. That means the ownership semantics are not used.
Suggest using a `T*` or `T&` instead.
**see also**:
**See also**:
* [prefer `t*` over `t&` when "no argument" is a valid option](#rf-ptr-ref)
@ -8084,7 +8093,7 @@ Casting to a reference expresses that you intend to end up with a valid object,
The `dynamic_cast` conversion allows to test whether a pointer is pointing at a polymorphic object that has a given class in its hierarchy. Since failure to find the class merely returns a null value, it can be tested during run time. This allows writing code that can choose alternative paths depending on the results.
Contrast with [C.147](#Rh-ptr-cast), where failure is an error, and should not be used for conditional execution.
Contrast with [C.147](#Rh-ref-cast), where failure is an error, and should not be used for conditional execution.
##### Example
@ -10429,7 +10438,7 @@ A structured binding (C++17) is specifically designed to introduce several varia
or better using concepts:
bool any_of(InputIterator first, InputIterator last, Predicate pred);
bool any_of(input_iterator auto first, input_iterator auto last, predicate auto pred);
##### Example
@ -10495,10 +10504,10 @@ Avoid `auto` for initializer lists and in cases where you know exactly which typ
##### Note
When concepts become available, we can (and should) be more specific about the type we are deducing:
As of C++20, we can (and should) use concepts to be more specific about the type we are deducing:
// ...
ForwardIterator p = algo(x, y, z);
forward_iterator auto p = algo(x, y, z);
##### Example (C++17)
@ -12814,11 +12823,11 @@ consider `gsl::finally()` as a cleaner and more reliable alternative to `goto ex
switch(x) {
case 1 :
while (/* some condition */) {
//...
//...
break;
} //Oops! break switch or break while intended?
} //Oops! break switch or break while intended?
case 2 :
//...
//...
break;
}
@ -12858,14 +12867,14 @@ Often, a loop that requires a `break` is a good candidate for a function (algori
Often, a loop that uses `continue` can equivalently and as clearly be expressed by an `if`-statement.
for (int item : vec) { //BAD
for (int item : vec) { //BAD
if (item%2 == 0) continue;
if (item == 5) continue;
if (item > 10) continue;
/* do something with item */
}
for (int item : vec) { //GOOD
for (int item : vec) { //GOOD
if (item%2 != 0 && item != 5 && item <= 10) {
/* do something with item */
}
@ -12912,6 +12921,7 @@ Multiple case labels of a single statement is OK:
}
Return statements in a case label are also OK:
switch (x) {
case 'a':
return 1;
@ -12953,7 +12963,7 @@ Flag all implicit fallthroughs from non-empty `case`s.
##### Example
enum E { a, b, c, d };
enum E { a, b, c, d };
void f1(E x)
{
@ -13107,10 +13117,10 @@ Helps make style consistent and conventional.
By definition, a condition in an `if`-statement, `while`-statement, or a `for`-statement selects between `true` and `false`.
A numeric value is compared to `0` and a pointer value to `nullptr`.
// These all mean "if `p` is not `nullptr`"
// These all mean "if p is not nullptr"
if (p) { ... } // good
if (p != 0) { ... } // redundant `!=0`; bad: don't use 0 for pointers
if (p != nullptr) { ... } // redundant `!=nullptr`, not recommended
if (p != 0) { ... } // redundant !=0, bad: don't use 0 for pointers
if (p != nullptr) { ... } // redundant !=nullptr, not recommended
Often, `if (p)` is read as "if `p` is valid" which is a direct expression of the programmers intent,
whereas `if (p != nullptr)` would be a long-winded workaround.
@ -13167,10 +13177,10 @@ would not in itself save you.
The opposite condition is most easily expressed using a negation:
// These all mean "if `p` is `nullptr`"
// These all mean "if p is nullptr"
if (!p) { ... } // good
if (p == 0) { ... } // redundant `== 0`; bad: don't use `0` for pointers
if (p == nullptr) { ... } // redundant `== nullptr`, not recommended
if (p == 0) { ... } // redundant == 0, bad: don't use 0 for pointers
if (p == nullptr) { ... } // redundant == nullptr, not recommended
##### Enforcement
@ -13700,11 +13710,11 @@ We can do better (in C++98)
Here, we use the compiler's knowledge about the size of the array, the type of elements, and how to compare `double`s.
With C++11 plus [concepts](#SS-concepts), we can do better still
With C++20, we can do better still
// Sortable specifies that c must be a
// sortable specifies that c must be a
// random-access sequence of elements comparable with <
void sort(Sortable& c);
void sort(sortable auto& c);
sort(c);
@ -13714,10 +13724,10 @@ They implicitly rely on the element type having less-than (`<`) defined.
To complete the interface, we need a second version that accepts a comparison criteria:
catch(int i) { // i == 7 means "input buffer too small"
// ...
}
}
// ...
##### Note
throw MyException{"something bad"}; // good
The standard-library classes derived from `exception` should be used only as base classes or for exceptions that require only "generic" handling. Like built-in types, their use could clash with other people's use of them.
Exceptions do not need to be derived from `std::exception`:
##### Example, don't
class MyCustomError final {}; // not derived from std::exception
void my_code() // Don't
{
// ...
throw runtime_error{"moon in the 4th quarter"};
// ...
}
// ...
void your_code() // Don't
{
try {
// ...
my_code();
// ...
}
catch(const runtime_error&) { // runtime_error means "input buffer too small"
// ...
}
}
throw MyCustomError{}; // good - handlers must catch this type (or ...)
**See also**: [Discussion](#Sd-???)
Library types derived from `std::exception` can be used as generic exceptions if
no useful information can be added at the point of detection:
throw std::runtime_error("someting bad"); // good
// ...
throw std::invalid_argument("i is not even"); // good
`enum` classes are also allowed:
enum class alert {RED, YELLOW, GREEN};
throw alert::RED; // good
##### Enforcement
Catch `throw` and `catch` of a built-in type. Maybe warn about `throw` and `catch` using a standard-library `exception` type. Obviously, exceptions derived from the `std::exception` hierarchy are fine.
Catch `throw` of built-in types and `std::exception`.
### <aname="Re-exception-ref"></a>E.15: Throw by value, catch exceptions from a hierarchy by reference
@ -16828,11 +16814,7 @@ In C++, these requirements are expressed by compile-time predicates called conce
Templates can also be used for meta-programming; that is, programs that compose code at compile time.
A central notion in generic programming is "concepts"; that is, requirements on template arguments presented as compile-time predicates.
"Concepts" are defined in an ISO Technical Specification: [concepts](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4553.pdf).
A draft of a set of standard-library concepts can be found in another ISO TS: [ranges](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4569.pdf).
Concepts are supported in GCC 6.1 and later.
Consequently, we comment out uses of concepts in examples; that is, we use them as formalized comments only.
If you use GCC 6.1 or later, you can uncomment them.
"Concepts" were standardized in C++20, although they were first made available, in slightly older syntax, in GCC 6.1.
Template use rule summary:
@ -16938,7 +16920,7 @@ Generality. Reuse. Efficiency. Encourages consistent definition of user types.
Conceptually, the following requirements are wrong because what we want of `T` is more than just the very low-level concepts of "can be incremented" or "can be added":
template<typenameT>
// requires Incrementable<T>
requires Incrementable<T>
T sum1(vector<T>& v, T s)
{
for (auto x : v) s += x;
@ -16946,7 +16928,7 @@ Conceptually, the following requirements are wrong because what we want of `T` i
}
template<typenameT>
// requires Simple_number<T>
requires Simple_number<T>
T sum2(vector<T>& v, T s)
{
for (auto x : v) s = s + x;
@ -16959,7 +16941,7 @@ And, in this case, missed an opportunity for a generalization.
##### Example
template<typenameT>
// requires Arithmetic<T>
requires Arithmetic<T>
T sum(vector<T>& v, T s)
{
for (auto x : v) s += x;
@ -16983,14 +16965,6 @@ We aim to minimize requirements on template arguments, but the absolutely minima
Templates can be used to express essentially everything (they are Turing complete), but the aim of generic programming (as expressed using templates)
is to efficiently generalize operations/algorithms over a set of types with similar semantic properties.
##### Note
The `requires` in the comments are uses of `concepts`.
"Concepts" are defined in an ISO Technical Specification: [concepts](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4553.pdf).
Concepts are supported in GCC 6.1 and later.
Consequently, we comment out uses of concepts in examples; that is, we use them as formalized comments only.
If you use GCC 6.1 or later, you can uncomment them.
##### Enforcement
* Flag algorithms with "overly simple" requirements, such as direct use of specific operators without a concept.
@ -17161,9 +17135,8 @@ See the reference to more specific rules.
"Concepts" are defined in an ISO Technical Specification: [concepts](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4553.pdf).
A draft of a set of standard-library concepts can be found in another ISO TS: [ranges](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4569.pdf).
Concepts are supported in GCC 6.1 and later.
Consequently, we comment out uses of concepts in examples; that is, we use them as formalized comments only.
If you use GCC 6.1 or later, you can uncomment them:
@ -17239,7 +17196,7 @@ Plain `typename` (or `auto`) is the least constraining concept.
It should be used only rarely when nothing more than "it's a type" can be assumed.
This is typically only needed when (as part of template metaprogramming code) we manipulate pure expression trees, postponing type checking.
**References**: TC++PL4, Palo Alto TR, Sutton
**References**: TC++PL4
##### Enforcement
@ -17249,26 +17206,26 @@ Flag template type arguments without concepts
##### Reason
"Standard" concepts (as provided by the [GSL](#S-gsl) and the [Ranges TS](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4569.pdf), and hopefully soon the ISO standard itself)
"Standard" concepts (as provided by the [GSL](#S-gsl) and the ISO standard itself)
save us the work of thinking up our own concepts, are better thought out than we can manage to do in a hurry, and improve interoperability.
##### Note
Unless you are creating a new generic library, most of the concepts you need will already be defined by the standard library.
This `Ordered_container` is quite plausible, but it is very similar to the `Sortable` concept in the GSL (and the Range TS).
This `Ordered_container` is quite plausible, but it is very similar to the `sortable` concept in the standard library.
Is it better? Is it right? Does it accurately reflect the standard's requirements for `sort`?
It is better and simpler just to use `Sortable`:
It is better and simpler just to use `sortable`:
void sort(Sortable& s); // better
void sort(sortable auto& s); // better
##### Note
@ -17291,11 +17248,11 @@ Hard.
`auto` is the weakest concept. Concept names convey more meaning than just `auto`.
##### Example (using TS concepts)
##### Example
vector<string> v{ "abc", "xyz" };
auto& x = v.front(); // bad
String& s = v.front(); // good (String is a GSL concept)
auto& x = v.front(); // bad
String auto& s = v.front(); // good (String is a GSL concept)
##### Enforcement
@ -17307,29 +17264,21 @@ Hard.
Readability. Direct expression of an idea.
##### Example (using TS concepts)
##### Example
To say "`T` is `Sortable`":
To say "`T` is `sortable`":
template<typenameT> // Correct but verbose: "The parameter is
// requires Sortable<T> // of type T which is the name of a type
void sort(T&); // that is Sortable"
requires sortable<T> // of type T which is the name of a type
void sort(T&); // that is sortable"
template<Sortable T> // Better (assuming support for concepts): "The parameter is of type T
template<sortable T> // Better: "The parameter is of type T
void sort(T&); // which is Sortable"
void sort(Sortable&); // Best (assuming support for concepts): "The parameter is Sortable"
void sort(sortable auto&); // 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.
##### Note
"Concepts" are defined in an ISO Technical Specification: [concepts](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4553.pdf).
A draft of a set of standard-library concepts can be found in another ISO TS: [ranges](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4569.pdf).
Concepts are supported in GCC 6.1 and later.
Consequently, we comment out uses of concepts in examples; that is, we use them as formalized comments only.
If you use a compiler that supports concepts (e.g., GCC 6.1 or later), you can remove the `//`.
##### Enforcement
* Not feasible in the short term when people convert from the `<typename T>` and `<class T`> notation.
@ -17342,7 +17291,7 @@ Concepts are meant to represent fundamental concepts in an application domain (h
Similarly throwing together a set of syntactic constraints to be used for the arguments for a single class or algorithm is not what concepts were designed for
and will not give the full benefits of the mechanism.
Obviously, defining concepts will be most useful for code that can use an implementation (e.g., GCC 6.1 or later),
Obviously, defining concepts is most useful for code that can use an implementation (e.g., C++20 or later)
but defining concepts is in itself a useful design technique and help catch conceptual errors and clean up the concepts (sic!) of an implementation.
### <aname="Rt-low"></a>T.20: Avoid "concepts" without meaningful semantics
@ -17353,12 +17302,14 @@ Concepts are meant to express semantic notions, such as "a number", "a range" of
Simple constraints, such as "has a `+` operator" and "has a `>` operator" cannot be meaningfully specified in isolation
and should be used only as building blocks for meaningful concepts, rather than in user code.
@ -17510,17 +17459,17 @@ A meaningful/useful concept has a semantic meaning.
Expressing these semantics in an informal, semi-formal, or formal way makes the concept comprehensible to readers and the effort to express it can catch conceptual errors.
Specifying semantics is a powerful design tool.
##### Example (using TS concepts)
##### Example
template<typenameT>
// The operators +, -, *, and / for a number are assumed to follow the usual mathematical rules
// axiom(T a, T b) { a + b == b + a; a - a == 0; a * (b + c) == a * b + a * c; /*...*/ }
concept Number = requires(T a, T b) {
{a + b} -> T; // the result of a + b is convertible to T
{a - b} -> T;
{a * b} -> T;
{a / b} -> T;
}
{a + b} -> convertible_to<T>;
{a - b} -> convertible_to<T>;
{a * b} -> convertible_to<T>;
{a / b} -> convertible_to<T>;
};
##### Note
@ -17539,18 +17488,18 @@ Once language support is available, the `//` in front of the axiom can be remove
The GSL concepts have well-defined semantics; see the Palo Alto TR and the Ranges TS.
##### Exception (using TS concepts)
##### Exception
Early versions of a new "concept" still under development will often just define simple sets of constraints without a well-specified semantics.
Finding good semantics can take effort and time.
An incomplete set of constraints can still be very useful:
@ -21916,7 +21886,7 @@ This section covers answers to frequently asked questions about these guidelines
### <aname="Faq-aims"></a>FAQ.1: What do these guidelines aim to achieve?
See the <ahref="#S-abstract">top of this page</a>. This is an open-source project to maintain modern authoritative guidelines for writing C++ code using the current C++ Standard (as of this writing, C++14). The guidelines are designed to be modern, machine-enforceable wherever possible, and open to contributions and forking so that organizations can easily incorporate them into their own corporate coding guidelines.
See the <ahref="#S-abstract">top of this page</a>. This is an open-source project to maintain modern authoritative guidelines for writing C++ code using the current C++ Standard. The guidelines are designed to be modern, machine-enforceable wherever possible, and open to contributions and forking so that organizations can easily incorporate them into their own corporate coding guidelines.
### <aname="Faq-announced"></a>FAQ.2: When and where was this work first announced?
@ -21944,11 +21914,11 @@ Because `isocpp` is the Standard C++ Foundation; the committee's repositories ar
### <aname="Faq-cpp98"></a>FAQ.8: Will there be a C++98 version of these Guidelines? a C++11 version?
No. These guidelines are about how to best use Standard C++14 (and, if you have an implementation available, the Concepts Technical Specification) and write code assuming you have a modern conforming compiler.
No. These guidelines are about how to best use modern standard C++ and write code assuming you have a modern conforming compiler.
### <aname="Faq-language-extensions"></a>FAQ.9: Do these guidelines propose new language features?
No. These guidelines are about how to best use Standard C++14 + the Concepts Technical Specification, and they limit themselves to recommending only those features.
No. These guidelines are about how to best use modern Standard C++, and they limit themselves to recommending only those features.
### <aname="Faq-markdown"></a>FAQ.10: What version of Markdown do these guidelines use?
@ -22295,7 +22265,7 @@ Never allow an error to be reported from a destructor, a resource deallocation f
void test()
{
std::array<Nefarious,10> arr; // this line can std::terminate(!)
std::array<Nefarious,10> arr; // this line can std::terminate()
}
The behavior of arrays is undefined in the presence of destructors that throw because there is no reasonable rollback behavior that could ever be devised. Just think: What code can the compiler generate for constructing an `arr` where, if the fourth object's constructor throws, the code has to give up and in its cleanup mode tries to call the destructors of the already-constructed objects ... and one or more of those destructors throws? There is no satisfactory answer.