isocpp / CppCoreGuidelines

The C++ Core Guidelines are a set of tried-and-true guidelines, rules, and best practices about coding in C++
http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines
Other
42.85k stars 5.44k forks source link

suggestion: R.n (extend R.35,R.36) for shared_ptr<widget>&& parameter #1781

Open ka-ba opened 3 years ago

ka-ba commented 3 years ago

Title might be like: R.n: Take a shared_ptr<widget>&& parameter to express that caller is expected to transfer "it's" reference count

I'm about to design this into an interface. The background thought is, that there is something like a "primary owner", although ownership is shared technically. shared_ptr is needed for some reason external to the function that takes the argument (in this case: weak_ptr are necessary to cross-reference objects owned by the smart pointers).

The envisioned situation at the callers side is constructing an object and handing it over to the "primary owner". To express that the caller is requested to transfer ownership instead of sharing it, a rvalue reference is used for the parameter. (Of course nothing technically prevents the caller from retaining a copy of the shared_ptr, but the interface expresses that the expectation is otherwise.)

bgloyer commented 3 years ago

I think almost the same effect can be acheived by passing the shared_ptr by value and having the caller std::move() its shared_ptr when calling the function. That has the advantage of being a more typical use of shared_ptr. Would that be close enough for your case?

MikeGitb commented 3 years ago

@bgloyer: Doesn't that goe completely against what @ka-ba wants to achieve? If you have a by value std::shared_ptr parameter nothing in the signature indicates that you are supposed to move ownership into the function for correctness and not just for performance.

neithernut commented 3 years ago

But what would be the point in that? The only situation where passing ownership of an std::shared_ptr is required for correctness would be if, for whatever reason, only a single strong reference must be held at a given point.

But with a std::shared_ptr, you always have to consider the possibility of other parties holding strong references anyway. The only situation where you can reason about this is right after creating it. However, if you really only want one strong reference to exist until a given point you'd likely use a std::unique_ptr and create a std::shared_ptr from that one afterwards. The only reason you couldn't would probably be if you somehow depend on shared_from_this at the same time.

If you need some random given std::shared_ptr to be the only strong reference to an object, and for it to stay that way (there may be std::weak_ptrs to the same object), than the only reasonable thing to do imo is to somehow convert it to some other type giving you that guarantee, e.g. std::unique_ptr. For such an interface, sure, you pretty much require taking ownership of the std::shared_ptr in order to not end up with at least one additional reference. But I'd argue that such an interface would be (a) too specific and (b) too far into expert territory that you'd need this to be part of this guideline.

MikeGitb commented 3 years ago

@neithernut : I don't know what @ka-ba's resons is. It might even be an XY-problem (if you want to do this, you might have a problem with your overall design). I'm just saying the suggestion doesn't have the desired properties.

ka-ba commented 3 years ago

@bgloyer : I would go with @MikeGitb , that taking the argument by value would go against my original proposal. It's not about giving the caller the opportunity to relinquish shared ownership (of course the caller can do that anyway), but to communicate to the caller that the function would want her/him to do that.

@neithernut : I cannot rule out, that the envisioned design might have a flaw in that point; I just can't think of a better one that gives me safe cross-references to objects that are owned somewhere else (safe in a multi-threaded environment). Owning by unique_ptr would not allow for such safe x-refs, obviously. Using weak_ptrs permit such a scenario, at the cost of the risk that unwanted share_ptr are stored somewhere else. To mitigate that risk a little bit, I thought about having the interface communicate the intention (at least at the possible points). Then I found that this case isn't covered in the guidelines. Maybe that's for good reason, but at least I wanted to propse it for discussion. But the discussion of possible solutions to the design question maybe doesn't belong here...

[NB: Sorry for answering late. Am using github quite infrequently.]