mirror of
https://github.com/isocpp/CppCoreGuidelines.git
synced 2025-12-17 20:54:41 +03:00
Merge pull request #209 from jlaire/typos-and-other-fixes
Typos and other fixes
This commit is contained in:
@@ -104,7 +104,7 @@ 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.
|
||||||
However, no topic that can help a programmer is out of bounds.
|
However, no topic that can help a programmer is out of bounds.
|
||||||
|
|
||||||
Our initial set of rules emphasize safety (of various forms) and simplicity.
|
Our initial set of rules emphasizes safety (of various forms) and simplicity.
|
||||||
They may very well be too strict.
|
They may very well be too strict.
|
||||||
We expect to have to introduce more exceptions to better accommodate real-world needs.
|
We expect to have to introduce more exceptions to better accommodate real-world needs.
|
||||||
We also need more rules.
|
We also need more rules.
|
||||||
@@ -158,7 +158,7 @@ However, we do believe that a program that uses a rule is less error-prone and m
|
|||||||
Often, rules also lead to faster/easier initial development.
|
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;
|
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
|
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,
|
("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").
|
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:
|
||||||
@@ -471,11 +471,11 @@ A programmer should be familiar with
|
|||||||
* [The ISO C++ standard library](#S-stdlib)
|
* [The ISO C++ standard library](#S-stdlib)
|
||||||
* Whatever foundation libraries are used for the current project(s)
|
* Whatever foundation libraries are used for the current project(s)
|
||||||
|
|
||||||
**Note**: Alternative formulation: Say what should be done, rather than just how it should be done
|
**Note**: Alternative formulation: Say what should be done, rather than just how it should be done.
|
||||||
|
|
||||||
**Note**: Some language constructs express intent better than others.
|
**Note**: Some language constructs express intent better than others.
|
||||||
|
|
||||||
**Example**: if two `int`s are meant to be the coordinates of a 2D point, say so:
|
**Example**: If two `int`s are meant to be the coordinates of a 2D point, say so:
|
||||||
|
|
||||||
drawline(int, int, int, int); // obscure
|
drawline(int, int, int, int); // obscure
|
||||||
drawline(Point, Point); // clearer
|
drawline(Point, Point); // clearer
|
||||||
@@ -724,7 +724,7 @@ or may only need part of the value that is more easily checked than the whole.
|
|||||||
Jet(float x, float y, float z, float e)
|
Jet(float x, float y, float z, float e)
|
||||||
:fx(x), fy(y), fz(z), fe(e)
|
:fx(x), fy(y), fz(z), fe(e)
|
||||||
{
|
{
|
||||||
// Should I check the here that the values are physically meaningful?
|
// Should I check here that the values are physically meaningful?
|
||||||
}
|
}
|
||||||
|
|
||||||
float m() const
|
float m() const
|
||||||
@@ -782,7 +782,7 @@ Prefer [RAII](#Rr-raii):
|
|||||||
Where feasible, replace owners with standard-library resource handles (as in the example above).
|
Where feasible, replace owners with standard-library resource handles (as in the example above).
|
||||||
Alternatively, mark an owner as such using `owner` from [the GSL](#S-gsl).
|
Alternatively, mark an owner as such using `owner` from [the GSL](#S-gsl).
|
||||||
* Look for naked `new` and `delete`
|
* Look for naked `new` and `delete`
|
||||||
* look for known resource allocating functions returning raw pointers (such as `fopen`, `malloc`, and `strdup`)
|
* Look for known resource allocating functions returning raw pointers (such as `fopen`, `malloc`, and `strdup`)
|
||||||
|
|
||||||
|
|
||||||
### <a name="Rp-waste"></a> P.9: Don't waste time or space
|
### <a name="Rp-waste"></a> P.9: Don't waste time or space
|
||||||
@@ -808,8 +808,8 @@ Prefer [RAII](#Rr-raii):
|
|||||||
if (p==nullptr) throw Nullptr_error{};
|
if (p==nullptr) throw Nullptr_error{};
|
||||||
int n = strlen(p);
|
int n = strlen(p);
|
||||||
auto buf = new char[n];
|
auto buf = new char[n];
|
||||||
for (int i = 0; i<n; ++i) buf[i] = p[i];
|
|
||||||
if (buf==nullptr) throw Allocation_error{};
|
if (buf==nullptr) throw Allocation_error{};
|
||||||
|
for (int i = 0; i<n; ++i) buf[i] = p[i];
|
||||||
// ... manipulate buffer ...
|
// ... manipulate buffer ...
|
||||||
X x;
|
X x;
|
||||||
x.ch = 'a';
|
x.ch = 'a';
|
||||||
@@ -933,7 +933,7 @@ Functions can be template functions and sets of functions can be classes or clas
|
|||||||
|
|
||||||
Who else might modify `data`?
|
Who else might modify `data`?
|
||||||
|
|
||||||
**Note**: global constants are useful.
|
**Note**: Global constants are useful.
|
||||||
|
|
||||||
**Note**: The rule against global variables applies to namespace scope variables as well.
|
**Note**: The rule against global variables applies to namespace scope variables as well.
|
||||||
|
|
||||||
@@ -973,9 +973,9 @@ That's part of the problem.
|
|||||||
return my_x;
|
return my_x;
|
||||||
}
|
}
|
||||||
|
|
||||||
This one of the most effective solution to problem related to initialization order.
|
This is one of the most effective solutions to problems related to initialization order.
|
||||||
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 objects 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.
|
||||||
@@ -989,7 +989,7 @@ and this useful technique is not an exception to the no-singleton rule.
|
|||||||
### <a name="Ri-typed"></a> I.4: Make interfaces precisely and strongly typed
|
### <a name="Ri-typed"></a> I.4: Make interfaces precisely and strongly typed
|
||||||
|
|
||||||
Reason: Types are the simplest and best documentation, have well-defined meaning, and are guaranteed to be checked at compile time.
|
Reason: Types are the simplest and best documentation, have well-defined meaning, and are guaranteed to be checked at compile time.
|
||||||
Also, precisely typed code often optimize better.
|
Also, precisely typed code is often optimized better.
|
||||||
|
|
||||||
**Example; don't**: Consider
|
**Example; don't**: Consider
|
||||||
|
|
||||||
@@ -1025,8 +1025,8 @@ Obviously, we cannot catch all errors through the static type system
|
|||||||
|
|
||||||
**Enforcement**:
|
**Enforcement**:
|
||||||
|
|
||||||
* (Simple) Report the use of void* as a parameter or return type.
|
* (Simple) Report the use of `void*` as a parameter or return type.
|
||||||
* (Hard to do well) Look for member functions with many built-in type arguments
|
* (Hard to do well) Look for member functions with many built-in type arguments.
|
||||||
|
|
||||||
|
|
||||||
### <a name="Ri-pre"></a> I.5: State preconditions (if any)
|
### <a name="Ri-pre"></a> I.5: State preconditions (if any)
|
||||||
@@ -1058,7 +1058,7 @@ We don't need to mention it for each member function.
|
|||||||
|
|
||||||
**Enforcement**: (Not enforceable)
|
**Enforcement**: (Not enforceable)
|
||||||
|
|
||||||
**See also**: the rules for passing pointers.
|
**See also**: The rules for passing pointers.
|
||||||
|
|
||||||
|
|
||||||
### <a name="Ri-expects"></a> I.6: Prefer `Expects()` for expressing preconditions
|
### <a name="Ri-expects"></a> I.6: Prefer `Expects()` for expressing preconditions
|
||||||
@@ -1080,7 +1080,7 @@ We don't need to mention it for each member function.
|
|||||||
|
|
||||||
**Note**: `Expects()` can also be used to check a condition in the middle of an algorithm.
|
**Note**: `Expects()` can also be used to check a condition in the middle of an algorithm.
|
||||||
|
|
||||||
**Enforcement**: (Not enforceable) Finding the variety of ways preconditions can be asserted is not feasible. Warning about those that can be easily identified (assert()) has questionable value in the absence of a language facility.
|
**Enforcement**: (Not enforceable) Finding the variety of ways preconditions can be asserted is not feasible. Warning about those that can be easily identified (`assert()`) has questionable value in the absence of a language facility.
|
||||||
|
|
||||||
|
|
||||||
### <a name="Ri-post"></a> I.7: State postconditions
|
### <a name="Ri-post"></a> I.7: State postconditions
|
||||||
@@ -1122,7 +1122,7 @@ There was no postcondition stating that the buffer should be cleared and the opt
|
|||||||
Ensures(buffer[0]==0);
|
Ensures(buffer[0]==0);
|
||||||
}
|
}
|
||||||
|
|
||||||
**Note** postconditions are often informally stated in a comment that states the purpose of a function; `Ensures()` can be used to make this more systematic, visible, and checkable.
|
**Note**: Postconditions are often informally stated in a comment that states the purpose of a function; `Ensures()` can be used to make this more systematic, visible, and checkable.
|
||||||
|
|
||||||
**Note**: Postconditions are especially important when they relate to something that is not directly reflected in a returned result, such as a state of a data structure used.
|
**Note**: Postconditions are especially important when they relate to something that is not directly reflected in a returned result, such as a state of a data structure used.
|
||||||
|
|
||||||
@@ -1175,13 +1175,13 @@ Postconditions related only to internal state belongs in the definition/implemen
|
|||||||
Ensures(buffer[0]==0);
|
Ensures(buffer[0]==0);
|
||||||
}
|
}
|
||||||
|
|
||||||
**Note**: postconditions can be stated in many ways, including comments, `if`-statements, and `assert()`. This can make them hard to distinguish from ordinary code, hard to update, hard to manipulate by tools, and may have the wrong semantics.
|
**Note**: Postconditions can be stated in many ways, including comments, `if`-statements, and `assert()`. This can make them hard to distinguish from ordinary code, hard to update, hard to manipulate by tools, and may have the wrong semantics.
|
||||||
|
|
||||||
**Alternative**: Postconditions of the form "this resource must be released" are best expressed by [RAII](#Rr-raii).
|
**Alternative**: Postconditions of the form "this resource must be released" are best expressed by [RAII](#Rr-raii).
|
||||||
|
|
||||||
Ideally, that `Ensures` should be part of the interface that's not easily done. For now, we place it in the definition (function body).
|
Ideally, that `Ensures` should be part of the interface, but that's not easily done. For now, we place it in the definition (function body).
|
||||||
|
|
||||||
**Enforcement**: (Not enforceable) Finding the variety of ways postconditions can be asserted is not feasible. Warning about those that can be easily identified (assert()) has questionable value in the absence of a language facility.
|
**Enforcement**: (Not enforceable) Finding the variety of ways postconditions can be asserted is not feasible. Warning about those that can be easily identified (`assert()`) has questionable value in the absence of a language facility.
|
||||||
|
|
||||||
|
|
||||||
### <a name="Ri-concepts"></a> I.9: If an interface is a template, document its parameters using concepts
|
### <a name="Ri-concepts"></a> I.9: If an interface is a template, document its parameters using concepts
|
||||||
@@ -1201,7 +1201,7 @@ Ideally, that `Ensures` should be part of the interface that's not easily done.
|
|||||||
|
|
||||||
**See also**: See [generic programming](???) and [???](???)
|
**See also**: See [generic programming](???) and [???](???)
|
||||||
|
|
||||||
**Enforcement**: (Not enforceable yet) 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.
|
**Enforcement**: (Not enforceable yet) 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).
|
||||||
|
|
||||||
|
|
||||||
### <a name="Ri-except"></a> I.10: Use exceptions to signal a failure to perform a required task
|
### <a name="Ri-except"></a> I.10: Use exceptions to signal a failure to perform a required task
|
||||||
@@ -1224,7 +1224,7 @@ For example, not being able to connect to a remote server is not by itself an er
|
|||||||
the server can refuse a connection for all kinds of reasons, so the natural thing is to return a result that the caller always has to check.
|
the server can refuse a connection for all kinds of reasons, so the natural thing is to return a result that the caller always has to check.
|
||||||
However, if failing to make a connection is considered an error, then a failure should throw an exception.
|
However, if failing to make a connection is considered an error, then a failure should throw an exception.
|
||||||
|
|
||||||
**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 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:
|
||||||
@@ -1249,7 +1249,7 @@ consider using a style that returns a pair of values:
|
|||||||
**Enforcement**:
|
**Enforcement**:
|
||||||
|
|
||||||
* (Not enforceable) This is a philosophical guideline that is infeasible to check directly.
|
* (Not enforceable) This is a philosophical guideline that is infeasible to check directly.
|
||||||
* look for `errno`.
|
* Look for `errno`.
|
||||||
|
|
||||||
|
|
||||||
### <a name="Ri-raw"></a> I.11: Never transfer ownership by a raw pointer (`T*`)
|
### <a name="Ri-raw"></a> I.11: Never transfer ownership by a raw pointer (`T*`)
|
||||||
@@ -1435,9 +1435,13 @@ Use `const` for the "from" argument:
|
|||||||
|
|
||||||
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)
|
||||||
|
|
||||||
|
**Example**: If the order of the parameters is not important, there is no problem:
|
||||||
|
|
||||||
|
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 b to q
|
void copy_n(array_view<const T> p, array_view<T> q); // copy from p to q
|
||||||
|
|
||||||
**Enforcement**: (Simple) Warn if two consecutive parameters share the same type.
|
**Enforcement**: (Simple) Warn if two consecutive parameters share the same type.
|
||||||
|
|
||||||
@@ -1480,9 +1484,9 @@ This will force every derived class to compute a center -- even if that's non-tr
|
|||||||
|
|
||||||
**Exception**: You can carefully craft an interface using a few carefully selected higher-level C++ types. See ???.
|
**Exception**: You can carefully craft an interface using a few carefully selected higher-level C++ types. See ???.
|
||||||
|
|
||||||
**Exception**: Common ABIs are emerging on some platforms freeing you from the more Draconian restrictions.
|
**Exception**: Common ABIs are emerging on some platforms freeing you from the more draconian restrictions.
|
||||||
|
|
||||||
**Note**: if you use a single compiler, you can use full C++ in interfaces. That may require recompilation after an upgrade to a new compiler version.
|
**Note**: If you use a single compiler, you can use full C++ in interfaces. That may require recompilation after an upgrade to a new compiler version.
|
||||||
|
|
||||||
**Enforcement**: (Not enforceable) It is difficult to reliably identify where an interface forms part of an ABI.
|
**Enforcement**: (Not enforceable) It is difficult to reliably identify where an interface forms part of an ABI.
|
||||||
|
|
||||||
@@ -1504,7 +1508,7 @@ Function definition rules:
|
|||||||
* [F.4: If a function may have to be evaluated at compile time, declare it `constexpr`](#Rf-constexpr)
|
* [F.4: If a function may have to be evaluated at compile time, declare it `constexpr`](#Rf-constexpr)
|
||||||
* [F.5: If a function is very small and time critical, declare it inline](#Rf-inline)
|
* [F.5: If a function is very small and time critical, declare it inline](#Rf-inline)
|
||||||
* [F.6: If your function may not throw, declare it `noexcept`](#Rf-noexcept)
|
* [F.6: If your function may not throw, declare it `noexcept`](#Rf-noexcept)
|
||||||
* [F.7: For general use, take `T*` arguments rather than a smart pointers](#Rf-smart)
|
* [F.7: For general use, take `T*` arguments rather than smart pointers](#Rf-smart)
|
||||||
* [F.8: Prefer pure functions](#Rf-pure)
|
* [F.8: Prefer pure functions](#Rf-pure)
|
||||||
|
|
||||||
Argument passing rules:
|
Argument passing rules:
|
||||||
@@ -1564,7 +1568,7 @@ If something is a well-specified action, separate it out from its surrounding c
|
|||||||
}
|
}
|
||||||
|
|
||||||
Almost everything is wrong with `read_and_print`.
|
Almost everything is wrong with `read_and_print`.
|
||||||
It reads, it writes (to a fixed `ostream`), it write error messages (to a fixed `ostream`), it handles only `int`s.
|
It reads, it writes (to a fixed `ostream`), it writes error messages (to a fixed `ostream`), it handles only `int`s.
|
||||||
There is nothing to reuse, logically separate operations are intermingled and local variables are in scope after the end of their logical use.
|
There is nothing to reuse, logically separate operations are intermingled and local variables are in scope after the end of their logical use.
|
||||||
For a tiny example, this looks OK, but if the input operation, the output operation, and the error handling had been more complicated the tangled
|
For a tiny example, this looks OK, but if the input operation, the output operation, and the error handling had been more complicated the tangled
|
||||||
mess could become hard to understand.
|
mess could become hard to understand.
|
||||||
@@ -1585,7 +1589,7 @@ Naming that lambda breaks up the expression into its logical parts and provides
|
|||||||
|
|
||||||
The shortest code is not always the best for performance or maintainability.
|
The shortest code is not always the best for performance or maintainability.
|
||||||
|
|
||||||
**Exception**: Loop bodies, including lambdas used as loop bodies, rarely needs to be named.
|
**Exception**: Loop bodies, including lambdas used as loop bodies, rarely need to be named.
|
||||||
However, large loop bodies (e.g., dozens of lines or dozens of pages) can be a problem.
|
However, large loop bodies (e.g., dozens of lines or dozens of pages) can be a problem.
|
||||||
The rule [Keep functions short](#Rf-single) implies "Keep loop bodies short."
|
The rule [Keep functions short](#Rf-single) implies "Keep loop bodies short."
|
||||||
Similarly, lambdas used as callback arguments are sometimes non-trivial, yet unlikely to be re-usable.
|
Similarly, lambdas used as callback arguments are sometimes non-trivial, yet unlikely to be re-usable.
|
||||||
@@ -1639,7 +1643,7 @@ If there was a need, we could further templatize `read()` and `print()` on the d
|
|||||||
{
|
{
|
||||||
input >> value;
|
input >> value;
|
||||||
// check for errors
|
// check for errors
|
||||||
}
|
};
|
||||||
|
|
||||||
auto print(auto& output, const auto& value)
|
auto print(auto& output, const auto& value)
|
||||||
{
|
{
|
||||||
@@ -1736,11 +1740,11 @@ Small simple functions are easily inlined where the cost of a function call is s
|
|||||||
constexpr int max_exp = 17; // constexpr enables this to be used in Expects
|
constexpr int max_exp = 17; // constexpr enables this to be used in Expects
|
||||||
Expects(0<=n && n<max_exp); // prevent silliness and overflow
|
Expects(0<=n && n<max_exp); // prevent silliness and overflow
|
||||||
int x = 1;
|
int x = 1;
|
||||||
for (int i=2; i<=n; ++i) x*= n;
|
for (int i=2; i<=n; ++i) x*= i;
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
This is C++14. For C++11, use a functional formulation of `fac()`.
|
This is C++14. For C++11, use a recursive formulation of `fac()`.
|
||||||
|
|
||||||
**Note**: `constexpr` does not guarantee compile-time evaluation;
|
**Note**: `constexpr` does not guarantee compile-time evaluation;
|
||||||
it just guarantees that the function can be evaluated at compile time for constant expression arguments if the programmer requires it or the compiler decides to do so to optimize.
|
it just guarantees that the function can be evaluated at compile time for constant expression arguments if the programmer requires it or the compiler decides to do so to optimize.
|
||||||
@@ -1825,11 +1829,11 @@ so don't just sprinkle `noexcept` all over the place.
|
|||||||
|
|
||||||
**Enforcement**:
|
**Enforcement**:
|
||||||
|
|
||||||
* Flag functions that are not `noexcept`, yet cannot throw
|
* Flag functions that are not `noexcept`, yet cannot throw.
|
||||||
* Flag throwing `swap`, `move`, destructors, and default constructors.
|
* Flag throwing `swap`, `move`, destructors, and default constructors.
|
||||||
|
|
||||||
|
|
||||||
### <a name="Rf-smart"></a> F.7: For general use, take `T*` arguments rather than a smart pointers
|
### <a name="Rf-smart"></a> F.7: For general use, take `T*` arguments rather than smart pointers
|
||||||
|
|
||||||
**Reason**: Passing a smart pointer transfers or shares ownership.
|
**Reason**: Passing a smart pointer transfers or shares ownership.
|
||||||
Passing by smart pointer restricts the use of a function to callers that use smart pointers.
|
Passing by smart pointer restricts the use of a function to callers that use smart pointers.
|
||||||
@@ -1861,7 +1865,7 @@ Passing a shared smart pointer (e.g., `std::shared_ptr`) implies a run-time cost
|
|||||||
|
|
||||||
**Note**: `constexpr` functions are pure.
|
**Note**: `constexpr` functions are pure.
|
||||||
|
|
||||||
**Enforcement**: not possible.
|
**Enforcement**: Not possible.
|
||||||
|
|
||||||
|
|
||||||
## <a name="SS-call"></a> F.call: Argument passing
|
## <a name="SS-call"></a> F.call: Argument passing
|
||||||
@@ -1893,7 +1897,7 @@ If you have multiple values to return, [use a tuple](#Rf-T-multi) or similar mul
|
|||||||
|
|
||||||
* For non-value types, such as types in an inheritance hierarchy, return the object by `unique_ptr` or `shared_ptr`.
|
* For non-value 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 non-`const` reference to a target object to fill (to be used as an out-parameter).
|
* 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 non-`const` reference to a target object to fill (to be used as an out-parameter).
|
||||||
* In the special case of allowing a caller 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 instead and pass by `&`. This one use of the more generally named "caller-allocated out" pattern.
|
* In the special case of allowing a caller 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 instead and pass by `&`. This is one use of the more generally named "caller-allocated out" pattern.
|
||||||
|
|
||||||
**For an "in-out" parameter:** Pass by non-`const` reference. This makes it clear to callers that the object is assumed to be modified.
|
**For an "in-out" parameter:** Pass by non-`const` reference. This makes it clear to callers that the object is assumed to be modified.
|
||||||
|
|
||||||
@@ -1947,7 +1951,7 @@ such as passing a `const int&`, returning an `array<BigPOD>` by value, and retur
|
|||||||
|
|
||||||
### <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**: In traditional C and C++ code, "Plain `T*` is used for many weakly-related purposes, such as
|
**Reason**: 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)
|
||||||
@@ -1956,7 +1960,6 @@ such as passing a `const int&`, returning an `array<BigPOD>` by value, and retur
|
|||||||
* Identify an array with a length specified separately
|
* Identify an array with a length specified separately
|
||||||
* Identify a location in an array
|
* Identify a location in an array
|
||||||
|
|
||||||
Using separate names for each of these uses improves code quality because confusion about the meaning of any particular `T*` is the source of many serious errors.
|
|
||||||
For example, `not_null<T*>` makes it obvious to a reader (human or machine) that a test for `nullptr` is not necessary before dereference.
|
For example, `not_null<T*>` makes it obvious to a reader (human or machine) that a test for `nullptr` is not necessary before dereference.
|
||||||
Additionally, when debugging, `owner<T*>` and `not_null<T>` can be instrumented to check for correctness.
|
Additionally, when debugging, `owner<T*>` and `not_null<T>` can be instrumented to check for correctness.
|
||||||
|
|
||||||
@@ -1971,11 +1974,11 @@ When I call `length(r)` should I test for `r==nullptr` first? Should the impleme
|
|||||||
|
|
||||||
int length(Record* p); // the implementor of length() must assume that p==nullptr is possible
|
int length(Record* p); // the implementor of length() must assume that p==nullptr is possible
|
||||||
|
|
||||||
**Note**: A `not_null<T>` is assumed not to be the `nullptr`; a `T*` may be the `nullptr`; both can be represented in memory as a `T*` (so no run-time overhead is implied).
|
**Note**: A `not_null<T*>` is assumed not to be the `nullptr`; a `T*` may be the `nullptr`; both can be represented in memory as a `T*` (so no run-time overhead is implied).
|
||||||
|
|
||||||
**Note**: `owner<T*>` represents ownership.
|
**Note**: `owner<T*>` represents ownership.
|
||||||
|
|
||||||
**Also**: Assume that a `T*` obtained from a smart pointer to `T` (e.g., unique_ptr<`T`>) points to a single element.
|
**Also**: Assume that a `T*` obtained from a smart pointer to `T` (e.g., `unique_ptr<T>`) points to a single element.
|
||||||
|
|
||||||
**See also**: [Support library](#S-gsl).
|
**See also**: [Support library](#S-gsl).
|
||||||
|
|
||||||
@@ -2014,7 +2017,7 @@ When I call `length(r)` should I test for `r==nullptr` first? Should the impleme
|
|||||||
|
|
||||||
**Example**:
|
**Example**:
|
||||||
|
|
||||||
X* find(array_view<X> r, const X& v) // find v in r
|
X* find(array_view<X> r, const X& v); // find v in r
|
||||||
|
|
||||||
vector<X> vec;
|
vector<X> vec;
|
||||||
// ...
|
// ...
|
||||||
@@ -2022,7 +2025,7 @@ When I call `length(r)` should I test for `r==nullptr` first? Should the impleme
|
|||||||
|
|
||||||
**Note**: Ranges are extremely common in C++ code. Typically, they are implicit and their correct use is very hard to ensure. In particular, given a pair of arguments `(p, n)` designating an array [`p`:`p+n`), it is in general impossible to know if there really are n elements to access following `*p`. `array_view<T>` and `array_view_p<T>` are simple helper classes designating a [p:q) range and a range starting with p and ending with the first element for which a predicate is true, respectively.
|
**Note**: Ranges are extremely common in C++ code. Typically, they are implicit and their correct use is very hard to ensure. In particular, given a pair of arguments `(p, n)` designating an array [`p`:`p+n`), it is in general impossible to know if there really are n elements to access following `*p`. `array_view<T>` and `array_view_p<T>` are simple helper classes designating a [p:q) range and a range starting with p and ending with the first element for which a predicate is true, respectively.
|
||||||
|
|
||||||
**Note**: an `array_view<T>` object does not own its elements and is so small that it can be passed by value.
|
**Note**: An `array_view<T>` object does not own its elements and is so small that it can be passed by value.
|
||||||
|
|
||||||
**Note**: Passing an `array_view` object as an argument is exactly as efficient as passing a pair of pointer arguments or passing a pointer and an integer count.
|
**Note**: Passing an `array_view` object as an argument is exactly as efficient as passing a pair of pointer arguments or passing a pointer and an integer count.
|
||||||
|
|
||||||
@@ -2140,7 +2143,7 @@ If the writer of `g()` makes an assumption about the size of `buffer` a bad logi
|
|||||||
void fill(Package&); // OK
|
void fill(Package&); // OK
|
||||||
|
|
||||||
int val(); // OK
|
int val(); // OK
|
||||||
val(int&); // Bad: Is val reading its argument
|
void val(int&); // Bad: Is val reading its argument
|
||||||
|
|
||||||
**Enforcement**: Hard to choose a cutover value for the size of the value returned.
|
**Enforcement**: Hard to choose a cutover value for the size of the value returned.
|
||||||
|
|
||||||
@@ -2181,8 +2184,8 @@ If you have performance justification to optimize for rvalues, overload on `&&`
|
|||||||
|
|
||||||
**Enforcement**:
|
**Enforcement**:
|
||||||
|
|
||||||
* Flag all `X&&` parameters (where `X` is not a template type parameter name) and uses it without `std::move`.
|
* Flag all `X&&` parameters (where `X` is not a template type parameter name) and code that uses them without `std::move`.
|
||||||
* Flag access to moved-from objects
|
* Flag access to moved-from objects.
|
||||||
|
|
||||||
|
|
||||||
### <a name="Rf-unique_ptr"></a> F.26: Use a `unique_ptr<T>` to transfer ownership where a pointer is needed
|
### <a name="Rf-unique_ptr"></a> F.26: Use a `unique_ptr<T>` to transfer ownership where a pointer is needed
|
||||||
@@ -2213,7 +2216,7 @@ If you have performance justification to optimize for rvalues, overload on `&&`
|
|||||||
|
|
||||||
**Example**:
|
**Example**:
|
||||||
|
|
||||||
shared_ptr<Image> im { read_image(somewhere); };
|
shared_ptr<Image> im { read_image(somewhere) };
|
||||||
|
|
||||||
std::thread t0 {shade, args0, top_left, im};
|
std::thread t0 {shade, args0, top_left, im};
|
||||||
std::thread t1 {shade, args1, top_right, im};
|
std::thread t1 {shade, args1, top_right, im};
|
||||||
@@ -2369,8 +2372,8 @@ This applies to references as well:
|
|||||||
|
|
||||||
Here on one popular implementation I got the output
|
Here on one popular implementation I got the output
|
||||||
|
|
||||||
*p == 9
|
*p == 999
|
||||||
cx == 999
|
gx == 999
|
||||||
|
|
||||||
I expected that because the call of `g()` reuses the stack space abandoned by the call of `f()` so `*p` refers to the space now occupied by `gx`.
|
I expected that because the call of `g()` reuses the stack space abandoned by the call of `f()` so `*p` refers to the space now occupied by `gx`.
|
||||||
|
|
||||||
@@ -2381,7 +2384,7 @@ Imagine what a cracker could do with that dangling pointer.
|
|||||||
|
|
||||||
Fortunately, most (all?) modern compilers catch and warn against this simple case.
|
Fortunately, most (all?) modern compilers catch and warn against this simple case.
|
||||||
|
|
||||||
**Note**: you can construct similar examples using references.
|
**Note**: You can construct similar examples using references.
|
||||||
|
|
||||||
**Note**: This applies only to non-`static` local variables.
|
**Note**: This applies only to non-`static` local variables.
|
||||||
All `static` variables are (as their name indicates) statically allocated, so that pointers to them cannot dangle.
|
All `static` variables are (as their name indicates) statically allocated, so that pointers to them cannot dangle.
|
||||||
@@ -2593,14 +2596,14 @@ Subsections:
|
|||||||
|
|
||||||
**Note**: From a language perspective `class` and `struct` differ only in the default visibility of their members.
|
**Note**: From a language perspective `class` and `struct` differ only in the default visibility of their members.
|
||||||
|
|
||||||
**Enforcement**: Probably impossible. Maybe a heuristic looking for date items used together is possible.
|
**Enforcement**: Probably impossible. Maybe a heuristic looking for data items used together is possible.
|
||||||
|
|
||||||
|
|
||||||
### <a name="Rc-struct"></a> C.2: Use `class` if the class has an invariant; use `struct` if the data members can vary independently
|
### <a name="Rc-struct"></a> C.2: Use `class` if the class has an invariant; use `struct` if the data members can vary independently
|
||||||
|
|
||||||
**Reason**: Ease of comprehension. The use of `class` alerts the programmer to the need for an invariant
|
**Reason**: Ease of comprehension. The use of `class` alerts the programmer to the need for an invariant.
|
||||||
|
|
||||||
**Note**: An invariant is logical condition for the members of an object that a constructor must establish for the public member functions to assume. After the invariant is established (typically by a constructor) every member function can be called for the object. An invariant can be stated informally (e.g., in a comment) or more formally using `Expects`.
|
**Note**: An invariant is a logical condition for the members of an object that a constructor must establish for the public member functions to assume. After the invariant is established (typically by a constructor) every member function can be called for the object. An invariant can be stated informally (e.g., in a comment) or more formally using `Expects`.
|
||||||
|
|
||||||
**Example**:
|
**Example**:
|
||||||
|
|
||||||
@@ -2626,7 +2629,7 @@ but
|
|||||||
|
|
||||||
### <a name="Rc-interface"></a> C.3: Represent the distinction between an interface and an implementation using a class
|
### <a name="Rc-interface"></a> C.3: Represent the distinction between an interface and an implementation using a class
|
||||||
|
|
||||||
**Reason**: an explicit distinction between interface and implementation improves readability and simplifies maintenance.
|
**Reason**: An explicit distinction between interface and implementation improves readability and simplifies maintenance.
|
||||||
|
|
||||||
**Example**:
|
**Example**:
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user