From 7d3ff3c0b1092ad97a86c71ffaa2efaa488a7f2d Mon Sep 17 00:00:00 2001 From: hsutter Date: Tue, 1 Dec 2015 07:58:37 -0800 Subject: [PATCH] Merged F.23 into F.15 (issue #1) --- CppCoreGuidelines.md | 51 +++++++++++++++++--------------------------- 1 file changed, 20 insertions(+), 31 deletions(-) diff --git a/CppCoreGuidelines.md b/CppCoreGuidelines.md index 315329f..c040357 100644 --- a/CppCoreGuidelines.md +++ b/CppCoreGuidelines.md @@ -1785,7 +1785,6 @@ Argument passing rules: * [F.17: Use a `not_null` to indicate "null" is not a valid value](#Rf-nullptr) * [F.18: Use a `span` or a `span_p` to designate a half-open sequence](#Rf-range) * [F.19: Use a `zstring` or a `not_null` to designate a C-style string](#Rf-string) -* [F.23: Use `T&` for an out-parameter that is expensive to move (only)](#Rf-T-return-out) * [F.24: Use a `TP&&` parameter when forwarding (only)](#Rf-pass-ref-ref) * [F.25: Use a `T&&` parameter together with `move` for rare optimization opportunities](#Rf-pass-ref-move) * [F.26: Use a `unique_ptr` to transfer ownership where a pointer is needed](#Rf-unique_ptr) @@ -2196,16 +2195,18 @@ If you really feel the need for an optimization beyond the common techniques, me ![Normal parameter passing table](./param-passing-normal.png "Normal parameter passing") **For an "output-only" value:** Prefer return values to output parameters. -This includes large objects like standard containers that use implicit move operations for performance and to avoid explicit memory management. +This includes large objects like standard containers that use implicit move operations for performance and to avoid explicit memory management. A return value is harder to miss and harder to misuse than a `T&` (an in-out parameter). If you have multiple values to return, [use a tuple](#Rf-T-multi) or similar multi-member type. ##### Example - vector find_all(const vector&, int x); // return pointers to elements with the value x + vector find_all(const vector&, int x); // OK: return pointers to elements with the value x -##### Example, bad + void find_all(const vector&, vector& out, int x); // Bad: place pointers to elements with value x in out - void find_all(const vector&, vector& out, int x); // place pointers to elements with value x in out +##### Note + +A struct of many (individually cheap-to-move) elements may be in aggregate expensive to move. ##### Exceptions @@ -2213,6 +2214,20 @@ If you have multiple values to return, [use a tuple](#Rf-T-multi) or similar mul * If a type is expensive to move (e.g., `array`), 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 is one use of the more generally named "caller-allocated out" pattern. +##### Example + + struct Package { // exceptional case: expensive-to-move object + char header[16]; + char load[2024 - 16]; + }; + + Package fill(); // Bad: large return value + void fill(Package&); // OK + + int val(); // OK + void val(int&); // Bad: Is val reading its argument + + **For an "in-out" parameter:** Pass by non-`const` reference. This makes it clear to callers that the object is assumed to be modified. ##### Example @@ -2443,32 +2458,6 @@ When I call `length(s)` should I test for `s == nullptr` first? Should the imple **See also**: [Support library](#S-gsl). -### F.23: Use `T&` for an out-parameter that is expensive to move (only) - -##### Reason - -A return value is harder to miss and harder to misuse than a `T&` (an in-out parameter); [see also](#Rf-T-return); [see also](#Rf-T-multi). - -##### Example - - struct Package { - char header[16]; - char load[2024 - 16]; - }; - - Package fill(); // Bad: large return value - void fill(Package&); // OK - - int val(); // OK - void val(int&); // Bad: Is val reading its argument - -##### Enforcement - -Hard to choose a cutover value for the size of the value returned. - -##### Note -A struct of many (individually cheap-to-move) elements may be in aggregate expensive to move. - ### F.24: Use a `TP&&` parameter when forwarding (only) ##### Reason