SharedPtr.hpp
1 #ifndef OPALS_SHARED_PTR_HPP_INCLUDED
2 #define OPALS_SHARED_PTR_HPP_INCLUDED
3 
4 #include <opals/config.hpp>
5 #include <opals/ObjectBase.hpp>
6 #include <opals/fwd.hpp>
7 
8 #pragma once
9 
10 namespace opals
11 {
12  struct SharedPtrImpl;
13 
14  OPALS_API void shared_ptr_create(SharedPtrImpl *&, void *obj, void(*deleter)(void *));
15  OPALS_API void shared_ptr_create(SharedPtrImpl *&, ObjectBase *obj);
16  OPALS_API void shared_ptr_inc(SharedPtrImpl *&);
17  OPALS_API void shared_ptr_dec(SharedPtrImpl *&);
18  OPALS_API unsigned int shared_ptr_get_count(SharedPtrImpl * const &);
19  OPALS_API void* shared_ptr_get(SharedPtrImpl * const &);
20  OPALS_API void* shared_ptr_release(SharedPtrImpl *&);
21 
22  /** \brief smart pointer class for opals objects
23 
24  Smart pointers uses a reference counting mechanism to control the life time of an object. When the last
25  SharePtr instance goes out of scope, the controlled object is deleted. In case an object is shared across
26  dll boundaries, it is essential create and delete objects within the same heap. To do so you can either
27  provide a corresponding delete function (only non-member functions are supported) or an object is derived
28  from ObjectBase and the (overloaded) Delete function is called to delete the object.
29 
30  \author JO
31  \date 29.01.2019
32  */
33  template <typename T>
34  class SharedPtr
35  {
36  SharedPtrImpl *pimpl_;
37 
38  public:
39  SharedPtr() noexcept : pimpl_(0) {}
40  /// Put an object that is derived from ObjectBase under the control of the smart pointer class
41  SharedPtr(ObjectBase *obj) noexcept : pimpl_(0) { shared_ptr_create(pimpl_, obj); }
42  /// Put an object under the control of the smart pointer class with the corresponding deleter function pointer
43  SharedPtr(T *obj, void(*deleter)(void *)) noexcept : pimpl_(0) { shared_ptr_create(pimpl_, obj, deleter); }
44  SharedPtr(const SharedPtr &ref) noexcept : pimpl_(ref.pimpl_) { shared_ptr_inc(pimpl_); }
45 
46  ~SharedPtr() noexcept { shared_ptr_dec(pimpl_); }
47 
48  SharedPtr &operator=(const SharedPtr &h) {
49  SharedPtr tmp = h;
50  swap(tmp);
51  return *this;
52  }
53 
54  /// reset shared pointer and delete controlled object if necessary
55  void reset() noexcept {
56  SharedPtr tmp;
57  swap(tmp);
58  }
59  /// put a new ObjectBase object under the shared pointer control
60  void reset(ObjectBase *obj) noexcept {
61  SharedPtr tmp(obj);
62  swap(tmp);
63  }
64  /// put a new object under the shared pointer control (with the corresponding deleter function pointer)
65  void reset(T *obj, void(*deleter)(void *)) noexcept {
66  SharedPtr tmp(obj, deleter);
67  swap(tmp);
68  }
69  void swap(SharedPtr &h) noexcept {
70  std::swap(pimpl_, h.pimpl_);
71  }
72  /// get pointer to controlled object
73  T* get() const noexcept { return (T *)shared_ptr_get(pimpl_); }
74 
75  const T& operator*() const { return *get(); }
76  T& operator*() { return *get(); }
77 
78  const T* operator->() const { return get(); }
79  T* operator->() { return get(); }
80 
81  /// get number of SharedPtr instances that reference the same object
82  unsigned int use_count() const noexcept { return shared_ptr_get_count(pimpl_); }
83  /// is the controlled object only referenced by this SharedPtr instance
84  bool unique() const noexcept { return (shared_ptr_get_count(pimpl_) == 1); }
85 
86  operator bool() const noexcept { return (pimpl_ != 0); }
87 
88  /// \brief release the controlled object
89  /// This is only possible if the controlled object is only referenced by the current SharedPtr instance.
90  /// The user has to take care of deleting the object.
91  T* release() {
92  if (unique() == true)
93  return (T*)shared_ptr_release(pimpl_);
94  else
95  return (T*)0;
96  }
97  };
98 
99 }
100 
101 #endif //OPALS_SHARED_PTR_HPP_INCLUDED