]> git.lizzy.rs Git - minetest.git/commitdiff
Improve irr_ptr (#10808)
authorVitaliy <numzer0@yandex.ru>
Sun, 24 Jan 2021 14:40:34 +0000 (17:40 +0300)
committerGitHub <noreply@github.com>
Sun, 24 Jan 2021 14:40:34 +0000 (14:40 +0000)
src/irr_ptr.h

index 5022adb9d6fdc0f19ea418a683716f818c0bf89c..42b409676123724578b720f8a10595468368b418 100644 (file)
@@ -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<scene::IMeshBuffer> 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 <class ReferenceCounted,
                class = typename std::enable_if<std::is_base_of<IReferenceCounted,
@@ -38,16 +43,6 @@ class irr_ptr
 {
        ReferenceCounted *value = nullptr;
 
-       /** Drops stored pointer replacing it with the given one.
-        * @note Copy semantics: reference counter *is* increased.
-        */
-       void grab(ReferenceCounted *object)
-       {
-               if (object)
-                       object->grab();
-               reset(object);
-       }
-
 public:
        irr_ptr() {}
 
@@ -71,8 +66,10 @@ class irr_ptr
                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 @@ class irr_ptr
                        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 <class ReferenceCounted>
+irr_ptr<ReferenceCounted> grab(ReferenceCounted *object) noexcept
+{
+       irr_ptr<ReferenceCounted> ptr;
+       ptr.grab(object);
+       return ptr;
+}
+
+template <typename ReferenceCounted>
+bool operator==(const irr_ptr<ReferenceCounted> &a, const irr_ptr<ReferenceCounted> &b) noexcept
+{
+       return a.get() == b.get();
+}
+
+template <typename ReferenceCounted>
+bool operator==(const irr_ptr<ReferenceCounted> &a, const ReferenceCounted *b) noexcept
+{
+       return a.get() == b;
+}
+
+template <typename ReferenceCounted>
+bool operator==(const ReferenceCounted *a, const irr_ptr<ReferenceCounted> &b) noexcept
+{
+       return a == b.get();
+}
+
+template <typename ReferenceCounted>
+bool operator!=(const irr_ptr<ReferenceCounted> &a, const irr_ptr<ReferenceCounted> &b) noexcept
+{
+       return a.get() != b.get();
+}
+
+template <typename ReferenceCounted>
+bool operator!=(const irr_ptr<ReferenceCounted> &a, const ReferenceCounted *b) noexcept
+{
+       return a.get() != b;
+}
+
+template <typename ReferenceCounted>
+bool operator!=(const ReferenceCounted *a, const irr_ptr<ReferenceCounted> &b) noexcept
+{
+       return a != b.get();
+}
+
+// clang-format on