0

I am working with the API of a C++ library that takes lots of std::weak_ptrs as the input parameters of the API methods. The library does not keep these pointers and just does some processing on them. To me, this design is something like this from the library's point of view:

Hi API User,

You have passed me some weak pointers as the input parameter(s) of a method to get a service from the library. But your pointers may be expired and not valid anymore. OK, no problem, I will do the check and let you know about it.

BR, Library API

Isn't it more reasonable for the design of such an API to get all of the pointers using a std::shared_ptr? In this case, if the API user is working with weak_ptrs, it is the user's responsibility to .lock() the weak_ptr pointers first and then pass them to the API (if the .lock() is successful). Is there any cases that the API should just get the parameters as the std::weak_ptr not the std::shared_ptr?

p.s. There is a similar question here in S.O., but it does not clearly answer my question in general.

TonySalimi
  • 8,257
  • 4
  • 33
  • 62
  • There are at least technical reasons to use a weak_ptr sometimes like breaking ownership cycles. A notorious example with shared_ptr is with the Observer pattern with observers holding the subject and the subject holding the observers. – gast128 Dec 09 '19 at 10:21
  • 1
    "The library does not keep these pointers", so passing regular pointers or references seems better. – Jarod42 Dec 09 '19 at 17:23

2 Answers2

1

If the API methods take a long time to execute then the shared_ptrs would be locked for the duration of the execution if it took std::shared_ptr instead of std::weak_ptr. Whether this is a concern or not is difficult to tell without knowing the API.

I don't see any real disadvantage to this approach, there will be a small cost in converting from shared_ptr to weak_ptr and back to shared_ptr again and certainly a complexity cost in terms of the implementation though as it probably would have to check for null pointers anyway that cost is presumably small.

Alan Birtles
  • 32,622
  • 4
  • 31
  • 60
  • "If the API methods take a long time to execute then the shared_ptrs would be locked for the duration of the execution" -> If the parameters are `weak_ptr`, then the API first `.lock()`s the object and then it will be the same as before, No? – TonySalimi Dec 09 '19 at 10:51
  • Yes it would be the same but if the API only required an object for some of its execution it could lock and release as needed – Alan Birtles Dec 09 '19 at 12:41
0

The rule I tend to follow is this: if the callee isn't mucking with lifetime/ownership, do not pass it a smart pointer; rather, pass in a raw C++ reference (preferred) or raw pointer. I find it far cleaner and more flexible to separate the concern of ownership from usage.

[Note: this is also my answer to a different question: what's the point of std::unique_ptr::get

Nevin
  • 4,595
  • 18
  • 24
  • If I design a piece of software with smart pointers, I will never use the raw pointers in the code. I believe that using `.get()` for smart pointers is out there just for compatibility with legacy old codes. – TonySalimi Dec 10 '19 at 09:24
  • If you are using references, you don't need to use `.get()`; `*p` works great, and doesn't conflate ownership with usage. – Nevin Dec 11 '19 at 01:53
  • But how I can pass a smart pointer to a method that takes a reference then? You mean sending the const-ref of the smart pointer? – TonySalimi Dec 11 '19 at 08:01
  • Yes, just pass a raw reference via `*p` (although whether it is by reference or reference to `const` is part of the API design). If the callee doesn't participate in ownership, then passing a smart pointer instead of a reference clutters the interface, makes it harder to reason about (you may have to look at the body of the callee to determine that indeed it does not participate in ownership) and adding an unnecessary constraint (your particular type of smart pointer). – Nevin Dec 11 '19 at 20:56