Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When would I want to construct a shared pointer from a raw pointer

Thanks to std::make_shared, I wonder, whether the constructor for std::shared_ptr, which takes a raw pointer has any value except when interfacing with legacy / library code, e.g. when storing the output of a factory.

  • Are there other legitimate use-cases?
  • Is it reasonable advice to avoid that constructor?
  • Even to the extend of putting code checks for it in place that warn the programmer whenever it is used?
  • Should the same guidelines (whatever they are) apply to shared_ptr<T>::reset(T*)?

Regarding the code checks: I know that interfacing with legacy / library code is quite common, so automated code checks might be problematic, but in most cases I encountered so far, I'd rather use a unique_ptr anyway and I'm also not talking about a compiler warning that pops up at -Wall, but rather about a rule for static code analysis during code review.


My motivation:
It is relatively easy to say "Don't use std::shared_ptr<T>(new T(...)), always prefer std::make_shared<T>(...)" (Which I believe is correct advise?). But I'm wondering if it isn't a design smell in general, if one has to create a shared_ptr from a raw pointer, even - or especially - if the object was not just created via new, because the object should have been created either as a "shared" or "unique" object in the first place.

like image 527
MikeMB Avatar asked Jul 24 '15 08:07

MikeMB


1 Answers

First use case that pops to mind is when the deleter is not the default delete.

E.g. in a windows environment COM objects must some times be used, the release of these objects must be done on the object itself, via Release. Sure ATL can be used, but not everyone wants to use it.

struct ReleaseCom {
  template <class T>
  void operator() (T* p) const
  {
    p->Release();
  }
};
IComInterface* p = // co created or returned as a result
std::share_ptr<IComInterface> sp(p, ReleaseCom());

A more uncommon situation - but still valid - is when an object (handle or even raw memory) is custom allocated in a dll, OS or library and has it's own associated cleanup function that must be called (which may or may not call delete in turn). If memory allocation is involved std::allocate_shared offers more enhanced control of the allocator that is to be used without exposing a raw pointer.

My personal feeling is that given std::make_shared and std::allocate_shared, the requirement to construct a shared_ptr from raw pointers is becoming less and less. Even the cases above, can be wrapped into utility allocation and management functions, removing from the main business logic code.

like image 131
Niall Avatar answered Sep 28 '22 01:09

Niall