mirror of
https://github.com/isocpp/CppCoreGuidelines.git
synced 2025-12-18 21:24:41 +03:00
update from master
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
# <a name="main"></a>C++ Core Guidelines
|
# <a name="main"></a>C++ Core Guidelines
|
||||||
|
|
||||||
September 29, 2023
|
October 12, 2023
|
||||||
|
|
||||||
Editors:
|
Editors:
|
||||||
|
|
||||||
@@ -2310,8 +2310,8 @@ So, we write a class
|
|||||||
public:
|
public:
|
||||||
enum Opt { from_line = 1 };
|
enum Opt { from_line = 1 };
|
||||||
Istream() { }
|
Istream() { }
|
||||||
Istream(zstring p) : owned{true}, inp{new ifstream{p}} {} // read from file
|
Istream(czstring p) : owned{true}, inp{new ifstream{p}} {} // read from file
|
||||||
Istream(zstring p, Opt) : owned{true}, inp{new istringstream{p}} {} // read from command line
|
Istream(czstring p, Opt) : owned{true}, inp{new istringstream{p}} {} // read from command line
|
||||||
~Istream() { if (owned) delete inp; }
|
~Istream() { if (owned) delete inp; }
|
||||||
operator istream&() { return *inp; }
|
operator istream&() { return *inp; }
|
||||||
private:
|
private:
|
||||||
@@ -3188,7 +3188,7 @@ A `struct` of many (individually cheap-to-move) elements might be in aggregate e
|
|||||||
##### Exceptions
|
##### Exceptions
|
||||||
|
|
||||||
* For non-concrete types, such as types in an inheritance hierarchy, return the object by `unique_ptr` or `shared_ptr`.
|
* For non-concrete types, such as types in an inheritance hierarchy, return the object by `unique_ptr` or `shared_ptr`.
|
||||||
* If a type is expensive to move (e.g., `array<BigPOD>`), consider allocating it on the free store and return a handle (e.g., `unique_ptr`), or passing it in a reference to non-`const` target object to fill (to be used as an out-parameter).
|
* If a type is expensive to move (e.g., `array<BigTrivial>`), consider allocating it on the free store and return a handle (e.g., `unique_ptr`), or passing it in a reference to non-`const` target object to fill (to be used as an out-parameter).
|
||||||
* To reuse an object that carries capacity (e.g., `std::string`, `std::vector`) across multiple calls to the function in an inner loop: [treat it as an in/out parameter and pass by reference](#Rf-out-multi).
|
* To reuse an object that carries capacity (e.g., `std::string`, `std::vector`) across multiple calls to the function in an inner loop: [treat it as an in/out parameter and pass by reference](#Rf-out-multi).
|
||||||
|
|
||||||
##### Example
|
##### Example
|
||||||
@@ -3301,7 +3301,7 @@ To compare, if we passed out all values as return values, we would something lik
|
|||||||
return {in, move(s)};
|
return {in, move(s)};
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto p = get_string(cin); p.first; ) {
|
for (auto p = get_string(cin); p.first; p.second = get_string(p.first).second) {
|
||||||
// do something with p.second
|
// do something with p.second
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6438,9 +6438,11 @@ A non-throwing move will be used more efficiently by standard-library and langua
|
|||||||
public:
|
public:
|
||||||
Vector(Vector&& a) noexcept :elem{a.elem}, sz{a.sz} { a.elem = nullptr; a.sz = 0; }
|
Vector(Vector&& a) noexcept :elem{a.elem}, sz{a.sz} { a.elem = nullptr; a.sz = 0; }
|
||||||
Vector& operator=(Vector&& a) noexcept {
|
Vector& operator=(Vector&& a) noexcept {
|
||||||
|
if (&a != this) {
|
||||||
delete elem;
|
delete elem;
|
||||||
elem = a.elem; a.elem = nullptr;
|
elem = a.elem; a.elem = nullptr;
|
||||||
sz = a.sz; a.sz = 0;
|
sz = a.sz; a.sz = 0;
|
||||||
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
// ...
|
// ...
|
||||||
@@ -10858,7 +10860,7 @@ The *always initialize* rule is a style rule aimed to improve maintainability as
|
|||||||
|
|
||||||
Here is an example that is often considered to demonstrate the need for a more relaxed rule for initialization
|
Here is an example that is often considered to demonstrate the need for a more relaxed rule for initialization
|
||||||
|
|
||||||
widget i; // "widget" a type that's expensive to initialize, possibly a large POD
|
widget i; // "widget" a type that's expensive to initialize, possibly a large trivial type
|
||||||
widget j;
|
widget j;
|
||||||
|
|
||||||
if (cond) { // bad: i and j are initialized "late"
|
if (cond) { // bad: i and j are initialized "late"
|
||||||
@@ -11093,7 +11095,8 @@ For containers, there is a tradition for using `{...}` for a list of elements an
|
|||||||
|
|
||||||
int x {7.9}; // error: narrowing
|
int x {7.9}; // error: narrowing
|
||||||
int y = 7.9; // OK: y becomes 7. Hope for a compiler warning
|
int y = 7.9; // OK: y becomes 7. Hope for a compiler warning
|
||||||
int z = gsl::narrow_cast<int>(7.9); // OK: you asked for it
|
int z {gsl::narrow_cast<int>(7.9)}; // OK: you asked for it
|
||||||
|
auto zz = gsl::narrow_cast<int>(7.9); // OK: you asked for it
|
||||||
|
|
||||||
##### Note
|
##### Note
|
||||||
|
|
||||||
@@ -11365,8 +11368,6 @@ Also, `#` and `##` encourages the definition and use of macros:
|
|||||||
|
|
||||||
There are workarounds for low-level string manipulation using macros. For example:
|
There are workarounds for low-level string manipulation using macros. For example:
|
||||||
|
|
||||||
string s = "asdf" "lkjh"; // ordinary string literal concatenation
|
|
||||||
|
|
||||||
enum E { a, b };
|
enum E { a, b };
|
||||||
|
|
||||||
template<int x>
|
template<int x>
|
||||||
@@ -11378,9 +11379,10 @@ There are workarounds for low-level string manipulation using macros. For exampl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void f(int x, int y)
|
void f()
|
||||||
{
|
{
|
||||||
string sx = stringify<x>();
|
string s1 = stringify<a>();
|
||||||
|
string s2 = stringify<b>();
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -16856,19 +16858,28 @@ Prevents accidental or hard-to-notice change of value.
|
|||||||
|
|
||||||
for (int i : c) cout << i << '\n'; // BAD: just reading
|
for (int i : c) cout << i << '\n'; // BAD: just reading
|
||||||
|
|
||||||
##### Exception
|
##### Exceptions
|
||||||
|
|
||||||
|
A local variable that is returned by value and is cheaper to move than copy should not be declared `const`
|
||||||
|
because it can force an unnecessary copy.
|
||||||
|
|
||||||
|
std::vector<int> f(int i)
|
||||||
|
{
|
||||||
|
std::vector<int> v{ i, i, i }; // const not needed
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
Function parameters passed by value are rarely mutated, but also rarely declared `const`.
|
Function parameters passed by value are rarely mutated, but also rarely declared `const`.
|
||||||
To avoid confusion and lots of false positives, don't enforce this rule for function parameters.
|
To avoid confusion and lots of false positives, don't enforce this rule for function parameters.
|
||||||
|
|
||||||
void f(const char* const p); // pedantic
|
|
||||||
void g(const int i) { ... } // pedantic
|
void g(const int i) { ... } // pedantic
|
||||||
|
|
||||||
Note that a function parameter is a local variable so changes to it are local.
|
Note that a function parameter is a local variable so changes to it are local.
|
||||||
|
|
||||||
##### Enforcement
|
##### Enforcement
|
||||||
|
|
||||||
* Flag non-`const` variables that are not modified (except for parameters to avoid many false positives)
|
* Flag non-`const` variables that are not modified (except for parameters to avoid many false positives
|
||||||
|
and returned local variables)
|
||||||
|
|
||||||
### <a name="Rconst-fct"></a>Con.2: By default, make member functions `const`
|
### <a name="Rconst-fct"></a>Con.2: By default, make member functions `const`
|
||||||
|
|
||||||
@@ -18437,21 +18448,22 @@ Specialization offers a powerful mechanism for providing alternative implementat
|
|||||||
|
|
||||||
This is a simplified version of `std::copy` (ignoring the possibility of non-contiguous sequences)
|
This is a simplified version of `std::copy` (ignoring the possibility of non-contiguous sequences)
|
||||||
|
|
||||||
struct pod_tag {};
|
struct trivially_copyable_tag {};
|
||||||
struct non_pod_tag {};
|
struct non_trivially_copyable_tag {};
|
||||||
|
|
||||||
template<class T> struct copy_trait { using tag = non_pod_tag; }; // T is not "plain old data"
|
// T is not trivially copyable
|
||||||
|
template<class T> struct copy_trait { using tag = non_trivially_copyable_tag; };
|
||||||
template<> struct copy_trait<int> { using tag = pod_tag; }; // int is "plain old data"
|
// int is trivially copyable
|
||||||
|
template<> struct copy_trait<int> { using tag = trivially_copyable_tag; };
|
||||||
|
|
||||||
template<class Iter>
|
template<class Iter>
|
||||||
Out copy_helper(Iter first, Iter last, Iter out, pod_tag)
|
Out copy_helper(Iter first, Iter last, Iter out, trivially_copyable_tag)
|
||||||
{
|
{
|
||||||
// use memmove
|
// use memmove
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Iter>
|
template<class Iter>
|
||||||
Out copy_helper(Iter first, Iter last, Iter out, non_pod_tag)
|
Out copy_helper(Iter first, Iter last, Iter out, non_trivially_copyable_tag)
|
||||||
{
|
{
|
||||||
// use loop calling copy constructors
|
// use loop calling copy constructors
|
||||||
}
|
}
|
||||||
@@ -18459,7 +18471,8 @@ This is a simplified version of `std::copy` (ignoring the possibility of non-con
|
|||||||
template<class Iter>
|
template<class Iter>
|
||||||
Out copy(Iter first, Iter last, Iter out)
|
Out copy(Iter first, Iter last, Iter out)
|
||||||
{
|
{
|
||||||
return copy_helper(first, last, out, typename copy_trait<Value_type<Iter>>::tag{})
|
using tag_type = typename copy_trait<std::iter_value_t<Iter>>;
|
||||||
|
return copy_helper(first, last, out, tag_type{})
|
||||||
}
|
}
|
||||||
|
|
||||||
void use(vector<int>& vi, vector<int>& vi2, vector<string>& vs, vector<string>& vs2)
|
void use(vector<int>& vi, vector<int>& vi2, vector<string>& vs, vector<string>& vs2)
|
||||||
@@ -18472,10 +18485,10 @@ This is a general and powerful technique for compile-time algorithm selection.
|
|||||||
|
|
||||||
##### Note
|
##### Note
|
||||||
|
|
||||||
When `concept`s become widely available such alternatives can be distinguished directly:
|
With C++20 constraints, such alternatives can be distinguished directly:
|
||||||
|
|
||||||
template<class Iter>
|
template<class Iter>
|
||||||
requires Pod<Value_type<Iter>>
|
requires std::is_trivially_copyable_v<std::iter_value_t<Iter>>
|
||||||
Out copy_helper(In, first, In last, Out out)
|
Out copy_helper(In, first, In last, Out out)
|
||||||
{
|
{
|
||||||
// use memmove
|
// use memmove
|
||||||
@@ -19208,6 +19221,7 @@ Source file rule summary:
|
|||||||
* [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.11: Header files should be self-contained](#Rs-contained)
|
||||||
* [SF.12: Prefer the quoted form of `#include` for files relative to the including file and the angle bracket form everywhere else](#Rs-incform)
|
* [SF.12: Prefer the quoted form of `#include` for files relative to the including file and the angle bracket form everywhere else](#Rs-incform)
|
||||||
|
* [SF.13: Use portable header identifiers in `#include` statements](#Rs-portable-header-id)
|
||||||
|
|
||||||
* [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)
|
||||||
@@ -19618,7 +19632,7 @@ Nevertheless, the guidance is to use the quoted form for including files that ex
|
|||||||
#include <string> // From the standard library, requires the <> form
|
#include <string> // From the standard library, requires the <> form
|
||||||
#include <some_library/common.h> // A file that is not locally relative, included from another library; use the <> form
|
#include <some_library/common.h> // A file that is not locally relative, included from another library; use the <> form
|
||||||
#include "foo.h" // A file locally relative to foo.cpp in the same project, use the "" form
|
#include "foo.h" // A file locally relative to foo.cpp in the same project, use the "" form
|
||||||
#include "foo_utils/utils.h" // A file locally relative to foo.cpp in the same project, use the "" form
|
#include "util/util.h" // A file locally relative to foo.cpp in the same project, use the "" form
|
||||||
#include <component_b/bar.h> // A file in the same project located via a search path, use the <> form
|
#include <component_b/bar.h> // A file in the same project located via a search path, use the <> form
|
||||||
|
|
||||||
##### Note
|
##### Note
|
||||||
@@ -19631,6 +19645,34 @@ Library creators should put their headers in a folder and have clients include t
|
|||||||
|
|
||||||
A test should identify whether headers referenced via `""` could be referenced with `<>`.
|
A test should identify whether headers referenced via `""` could be referenced with `<>`.
|
||||||
|
|
||||||
|
### <a name="Rs-portable-header-id"></a>SF.13: Use portable header identifiers in `#include` statements
|
||||||
|
|
||||||
|
##### Reason
|
||||||
|
|
||||||
|
The [standard](http://eel.is/c++draft/cpp.include) does not specify how compilers uniquely locate headers from an identifier in an `#include` directive, nor does it specify what constitutes uniqueness. For example, whether the implementation considers the identifiers to be case-sensitive, or whether the identifiers are file system paths to a header file, and if so, how a hierarchical file system path is delimited.
|
||||||
|
|
||||||
|
To maximize the portability of `#include` directives across compilers, guidance is to:
|
||||||
|
|
||||||
|
* use case-sensitivity for the header identifier, matching how the header is defined by the standard, specification, implementation, or file that provides the header.
|
||||||
|
* when the header identifier is a hierarchical file path, use forward-slash `/` to delimit path components as this is the most widely-accepted path-delimiting character.
|
||||||
|
|
||||||
|
##### Example
|
||||||
|
|
||||||
|
// good examples
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include "util/util.h"
|
||||||
|
|
||||||
|
// bad examples
|
||||||
|
#include <VECTOR> // bad: the standard library defines a header identified as <vector>, not <VECTOR>
|
||||||
|
#include <String> // bad: the standard library defines a header identified as <string>, not <String>
|
||||||
|
#include "Util/Util.H" // bad: the header file exists on the file system as "util/util.h"
|
||||||
|
#include "util\util.h" // bad: may not work if the implementation interprets `\u` as an escape sequence, or where '\' is not a valid path separator
|
||||||
|
|
||||||
|
##### Enforcement
|
||||||
|
|
||||||
|
It is only possible to enforce on implementations where header identifiers are case-sensitive and which only support `/` as a file path delimiter.
|
||||||
|
|
||||||
### <a name="Rs-namespace"></a>SF.20: Use `namespace`s to express logical structure
|
### <a name="Rs-namespace"></a>SF.20: Use `namespace`s to express logical structure
|
||||||
|
|
||||||
##### Reason
|
##### Reason
|
||||||
@@ -21594,7 +21636,8 @@ ISO Standard, use lower case only and digits, separate words with underscores:
|
|||||||
* `vector`
|
* `vector`
|
||||||
* `my_map`
|
* `my_map`
|
||||||
|
|
||||||
Avoid double underscores `__`.
|
Avoid identifier names that contain double underscores `__` or that start with an underscore followed by a capital letter (e.g., `_Throws`).
|
||||||
|
Such identifiers are reserved for the C++ implementation.
|
||||||
|
|
||||||
##### Example
|
##### Example
|
||||||
|
|
||||||
@@ -21643,7 +21686,7 @@ To avoid confusing macros with names that obey scope and type rules.
|
|||||||
|
|
||||||
##### Note
|
##### Note
|
||||||
|
|
||||||
This rule applies to non-macro symbolic constants:
|
In particular, this avoids confusing macros with non-macro symbolic constants (see also [Enum.5: Don't use `ALL_CAPS` for enumerators](#Renum-caps))
|
||||||
|
|
||||||
enum bad { BAD, WORSE, HORRIBLE }; // BAD
|
enum bad { BAD, WORSE, HORRIBLE }; // BAD
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user