84 lines
3.1 KiB
ReStructuredText
84 lines
3.1 KiB
ReStructuredText
.. _module-pw_intrusive_ptr:
|
|
|
|
----------------
|
|
pw_intrusive_ptr
|
|
----------------
|
|
|
|
IntrusivePtr
|
|
------------
|
|
``pw::IntrusivePtr`` is a smart shared pointer that relies on the pointed-at
|
|
object to do the reference counting. Its API is based on ``std::shared_ptr`` but
|
|
requires the pointed-at class to provide ``AddRef()`` and ``ReleaseRef()``
|
|
methods to do the reference counting. The easiest way to do that is to
|
|
subclass ``pw::RefCounted``. Doing this will provide atomic reference counting
|
|
and a ``Ptr`` type alias for the ``IntrusivePtr<T>``.
|
|
|
|
``IntrusivePtr`` doesn't provide any weak pointer ability.
|
|
|
|
``IntrusivePtr`` with a ``RefCounted``-based class always guarantees atomic
|
|
operations on the reference counter, whereas ``std::shared_ptr`` falls back to a
|
|
non-atomic control block when threading support is not enabled due to a design
|
|
fault in the STL implementation.
|
|
|
|
Similar to ``std::shared_ptr``, ``IntrusivePtr`` doesn't provide any
|
|
thread-safety guarantees for the pointed-at object or for the pointer object
|
|
itself. I.e. assigning and reading the same ``IntrusivePtr`` from multiple
|
|
threads without external lock is not allowed.
|
|
|
|
.. code-block:: cpp
|
|
|
|
class MyClass : public RefCounted<MyClass> {
|
|
// ...
|
|
};
|
|
|
|
// Empty pointer, equals to nullptr.
|
|
// MyClass::Ptr is the same as IntrusivePtr<MyClass>.
|
|
MyClass::Ptr empty_ptr = IntrusivePtr<MyClass>();
|
|
|
|
// Wrapping an externally created pointer.
|
|
MyClass raw_ptr = new MyClass();
|
|
MyClass::Ptr ptr_1 = MyClass::Ptr(raw_ptr);
|
|
// raw_ptr shouldn't be used after this line if ptr_1 can go out of scope.
|
|
|
|
// Using MakeRefCounted() helper.
|
|
auto ptr_2 = MakeRefCounted<MyClass>(/* ... */);
|
|
|
|
``IntrusivePtr`` can be passed as an argument by either const reference or
|
|
value. Const reference is more preferable because it does not cause unnecessary
|
|
copies (which results in atomic operations on the ref count). Passing by value
|
|
is used when this ``IntrusivePtr`` is immediately stored (e.g. constructor that
|
|
stores ``IntrusivePtr`` in the object field). In this case passing by value and
|
|
move is more explicit in terms of intentions. It is also the behavior that
|
|
clang-tidy checks suggest.
|
|
|
|
``IntrusivePtr`` should almost always be returned by value. The only case when
|
|
it can be returned by const reference is the trivial getter for the object
|
|
field. When returning locally created ``IntrusivePtr`` or a pointer that was
|
|
casted to the base class it MUST be returned by value.
|
|
|
|
Recyclable
|
|
----------
|
|
``pw::Recyclable`` is a mixin that can be used with supported smart pointers
|
|
like ``pw::IntrusivePtr`` to specify a custom memory cleanup routine instead
|
|
of `delete`. The cleanup routine is specified as a method with the signature
|
|
``void pw_recycle()``. For example:
|
|
|
|
.. code-block:: cpp
|
|
|
|
class Foo : public pw::Recyclable<Foo>, public pw::IntrusivePtr<Foo> {
|
|
public:
|
|
// public implementation here
|
|
private:
|
|
friend class pw::Recyclable<Foo>;
|
|
void pw_recycle() {
|
|
if (should_recycle())) {
|
|
do_recycle_stuff();
|
|
} else {
|
|
delete this;
|
|
}
|
|
}
|
|
};
|
|
|
|
``Recyclable`` can be used to avoid heap allocation when using smart pointers,
|
|
as the recycle routine can return memory to a memory pool.
|