From 30b41c32e3a5bb83a3b9d1df614e15fbb9317ab3 Mon Sep 17 00:00:00 2001 From: Sergey Zubkov Date: Thu, 1 Oct 2020 14:09:24 -0400 Subject: [PATCH] merge R.30 and F.7, closes #1671 (#1674) --- CppCoreGuidelines.md | 94 +++++++++++++++++++++------------------------------- 1 file changed, 37 insertions(+), 57 deletions(-) diff --git a/CppCoreGuidelines.md b/CppCoreGuidelines.md index b272dcb..e7767be 100644 --- a/CppCoreGuidelines.md +++ b/CppCoreGuidelines.md @@ -2735,8 +2735,12 @@ See also [C.44](#Rc-default00). ##### Reason -Passing a smart pointer transfers or shares ownership and should only be used when ownership semantics are intended (see [R.30](#Rr-smartptrparam)). +Passing a smart pointer transfers or shares ownership and should only be used when ownership semantics are intended. +A function that does not manipulate lifetime should take raw pointers or references instead. + Passing by smart pointer restricts the use of a function to callers that use smart pointers. +A function that needs a `widget` should be able to accept any `widget` object, not just ones whose lifetimes are managed by a particular kind of smart pointer. + Passing a shared smart pointer (e.g., `std::shared_ptr`) implies a run-time cost. ##### Example @@ -2766,24 +2770,45 @@ Passing a shared smart pointer (e.g., `std::shared_ptr`) implies a run-time cost // ... }; -See further in [R.30](#Rr-smartptrparam). + // caller + shared_ptr my_widget = /* ... */; + f(my_widget); -##### Note + widget stack_widget; + f(stack_widget); // error -We can catch dangling pointers statically, so we don't need to rely on resource management to avoid violations from dangling pointers. +##### Example, good -**See also**: + // callee + void f(widget& w) + { + // ... + use(w); + // ... + }; -* [Prefer `T*` over `T&` when "no argument" is a valid option](#Rf-ptr-ref) -* [Smart pointer rule summary](#Rr-summary-smartptrs) + // caller + shared_ptr my_widget = /* ... */; + f(*my_widget); + + widget stack_widget; + f(stack_widget); // ok -- now this works + +##### Note + +We can catch dangling pointers statically, so we don't need to rely on resource management to avoid violations from dangling pointers. ##### Enforcement -Flag a parameter of a smart pointer type (a type that overloads `operator->` or `operator*`) for which the ownership semantics are not used; -that is +* (Simple) Warn if a function takes a parameter of a smart pointer type (that overloads `operator->` or `operator*`) that is copyable but the function only calls any of: `operator*`, `operator->` or `get()`. + Suggest using a `T*` or `T&` instead. +* 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. -* copyable but never copied/moved from or movable but never moved -* and that is never modified or passed along to another function that could do so. +**see also**: + +* [prefer `t*` over `t&` when "no argument" is a valid option](#rf-ptr-ref) +* [smart pointer rule summary](#rr-summary-smartptrs) ### F.8: Prefer pure functions @@ -9626,52 +9651,7 @@ You could "temporarily share ownership" simply by using another `shared_ptr`.) ### R.30: Take smart pointers as parameters only to explicitly express lifetime semantics -##### Reason - -Accepting a smart pointer to a `widget` is wrong if the function just needs the `widget` itself. -It should be able to accept any `widget` object, not just ones whose lifetimes are managed by a particular kind of smart pointer. -A function that does not manipulate lifetime should take raw pointers or references instead. - -##### Example, bad - - // callee - void f(shared_ptr& w) - { - // ... - use(*w); // only use of w -- the lifetime is not used at all - // ... - }; - - // caller - shared_ptr my_widget = /* ... */; - f(my_widget); - - widget stack_widget; - f(stack_widget); // error - -##### Example, good - - // callee - void f(widget& w) - { - // ... - use(w); - // ... - }; - - // caller - shared_ptr my_widget = /* ... */; - f(*my_widget); - - widget stack_widget; - f(stack_widget); // ok -- now this works - -##### Enforcement - -* (Simple) Warn if a function takes a parameter of a smart pointer type (that overloads `operator->` or `operator*`) that is copyable but the function only calls any of: `operator*`, `operator->` or `get()`. - Suggest using a `T*` or `T&` instead. -* 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 [F.7](#Rf-smart). ### R.31: If you have non-`std` smart pointers, follow the basic pattern from `std` -- 2.11.4.GIT