diff --git a/src/irr_ptr.h b/src/irr_ptr.h index 5022adb9d..42b409676 100644 --- a/src/irr_ptr.h +++ b/src/irr_ptr.h @@ -27,9 +27,14 @@ with this program; if not, write to the Free Software Foundation, Inc., * It should only be used for user-managed objects, i.e. those created with * the @c new operator or @c create* functions, like: * `irr_ptr buf{new scene::SMeshBuffer()};` + * The reference counting is *not* balanced as new objects have reference + * count set to one, and the @c irr_ptr constructor (and @c reset) assumes + * ownership of that reference. * - * It should *never* be used for engine-managed objects, including - * those created with @c addTexture and similar methods. + * It shouldn’t be used for engine-managed objects, including those created + * with @c addTexture and similar methods. Constructing @c irr_ptr directly + * from such object is a bug and may lead to a crash. Indirect construction + * is possible though; see the @c grab free function for details and use cases. */ template grab(); - reset(object); - } - public: irr_ptr() {} @@ -71,8 +66,10 @@ public: reset(b.release()); } - /** Constructs a shared pointer out of a plain one + /** Constructs a shared pointer out of a plain one to control object lifetime. + * @param object The object, usually returned by some @c create* function. * @note Move semantics: reference counter is *not* increased. + * @warning Never wrap any @c add* function with this! */ explicit irr_ptr(ReferenceCounted *object) noexcept { reset(object); } @@ -134,4 +131,70 @@ public: value->drop(); value = object; } + + /** Drops stored pointer replacing it with the given one. + * @note Copy semantics: reference counter *is* increased. + */ + void grab(ReferenceCounted *object) noexcept + { + if (object) + object->grab(); + reset(object); + } }; + +// clang-format off +// ^ dislikes long lines + +/** Constructs a shared pointer as a *secondary* reference to an object + * + * This function is intended to make a temporary reference to an object which + * is owned elsewhere so that it is not destroyed too early. To acheive that + * it does balanced reference counting, i.e. reference count is increased + * in this function and decreased when the returned pointer is destroyed. + */ +template +irr_ptr grab(ReferenceCounted *object) noexcept +{ + irr_ptr ptr; + ptr.grab(object); + return ptr; +} + +template +bool operator==(const irr_ptr &a, const irr_ptr &b) noexcept +{ + return a.get() == b.get(); +} + +template +bool operator==(const irr_ptr &a, const ReferenceCounted *b) noexcept +{ + return a.get() == b; +} + +template +bool operator==(const ReferenceCounted *a, const irr_ptr &b) noexcept +{ + return a == b.get(); +} + +template +bool operator!=(const irr_ptr &a, const irr_ptr &b) noexcept +{ + return a.get() != b.get(); +} + +template +bool operator!=(const irr_ptr &a, const ReferenceCounted *b) noexcept +{ + return a.get() != b; +} + +template +bool operator!=(const ReferenceCounted *a, const irr_ptr &b) noexcept +{ + return a != b.get(); +} + +// clang-format on