1.. _module-pw_intrusive_ptr: 2 3---------------- 4pw_intrusive_ptr 5---------------- 6.. pigweed-module:: 7 :name: pw_intrusive_ptr 8 9IntrusivePtr 10------------ 11``pw::IntrusivePtr`` is a smart shared pointer that relies on the pointed-at 12object to do the reference counting. Its API is based on ``std::shared_ptr`` but 13requires the pointed-at class to provide ``AddRef()`` and ``ReleaseRef()`` 14methods to do the reference counting. The easiest way to do that is to 15subclass ``pw::RefCounted``. Doing this will provide atomic reference counting 16and a ``Ptr`` type alias for the ``IntrusivePtr<T>``. 17 18``IntrusivePtr`` doesn't provide any weak pointer ability. 19 20``IntrusivePtr`` with a ``RefCounted``-based class always guarantees atomic 21operations on the reference counter, whereas ``std::shared_ptr`` falls back to a 22non-atomic control block when threading support is not enabled due to a design 23fault in the STL implementation. 24 25Similar to ``std::shared_ptr``, ``IntrusivePtr`` doesn't provide any 26thread-safety guarantees for the pointed-at object or for the pointer object 27itself. I.e. assigning and reading the same ``IntrusivePtr`` from multiple 28threads without external lock is not allowed. 29 30.. code-block:: cpp 31 32 class MyClass : public RefCounted<MyClass> { 33 // ... 34 }; 35 36 // Empty pointer, equals to nullptr. 37 // MyClass::Ptr is the same as IntrusivePtr<MyClass>. 38 MyClass::Ptr empty_ptr = IntrusivePtr<MyClass>(); 39 40 // Wrapping an externally created pointer. 41 MyClass raw_ptr = new MyClass(); 42 MyClass::Ptr ptr_1 = MyClass::Ptr(raw_ptr); 43 // raw_ptr shouldn't be used after this line if ptr_1 can go out of scope. 44 45 // Using MakeRefCounted() helper. 46 auto ptr_2 = MakeRefCounted<MyClass>(/* ... */); 47 48``IntrusivePtr`` can be passed as an argument by either const reference or 49value. Const reference is more preferable because it does not cause unnecessary 50copies (which results in atomic operations on the ref count). Passing by value 51is used when this ``IntrusivePtr`` is immediately stored (e.g. constructor that 52stores ``IntrusivePtr`` in the object field). In this case passing by value and 53move is more explicit in terms of intentions. It is also the behavior that 54clang-tidy checks suggest. 55 56``IntrusivePtr`` should almost always be returned by value. The only case when 57it can be returned by const reference is the trivial getter for the object 58field. When returning locally created ``IntrusivePtr`` or a pointer that was 59casted to the base class it MUST be returned by value. 60 61Recyclable 62---------- 63``pw::Recyclable`` is a mixin that can be used with supported smart pointers 64like ``pw::IntrusivePtr`` to specify a custom memory cleanup routine instead 65of `delete`. The cleanup routine is specified as a method with the signature 66``void pw_recycle()``. For example: 67 68.. code-block:: cpp 69 70 class Foo : public pw::Recyclable<Foo>, public pw::IntrusivePtr<Foo> { 71 public: 72 // public implementation here 73 private: 74 friend class pw::Recyclable<Foo>; 75 void pw_recycle() { 76 if (should_recycle())) { 77 do_recycle_stuff(); 78 } else { 79 delete this; 80 } 81 } 82 }; 83 84``Recyclable`` can be used to avoid heap allocation when using smart pointers, 85as the recycle routine can return memory to a memory pool. 86