common: Add Deferred{Unique|Shared}Ptr and helpers
authorManuel Nickschas <sputnick@quassel-irc.org>
Tue, 1 Nov 2016 16:23:44 +0000 (17:23 +0100)
committerBen Rosser <rosser.bjr@gmail.com>
Sat, 27 May 2017 18:01:06 +0000 (14:01 -0400)
This commit adds smart pointers for holding QObject derivatives.
On destruction, they will deleteLater() the object they're holding.
This is the recommended and safe way for deleting QObject instances.
Be careful with using such smart pointers outside of the scope of
their parent, for objects that are owned. The parent will delete
its children, and any outside reference still held by a smart pointer
will lead to a double free!

src/common/deferredptr.h [new file with mode: 0644]

diff --git a/src/common/deferredptr.h b/src/common/deferredptr.h
new file mode 100644 (file)
index 0000000..1ea1f6b
--- /dev/null
@@ -0,0 +1,99 @@
+/***************************************************************************
+ *   Copyright (C) 2005-2016 by the Quassel Project                        *
+ *   devel@quassel-irc.org                                                 *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) version 3.                                           *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
+ ***************************************************************************/
+
+#pragma once
+
+#include <memory>
+#include <type_traits>
+
+#include <QObject>
+
+namespace detail {
+
+/**
+ * Deleter for storing QObjects in STL containers and smart pointers
+ *
+ * QObject should always be deleted by calling deleteLater() on them, so the event loop can
+ * perform necessary cleanups.
+ */
+struct DeferredDeleter {
+    /// Deletes the given QObject
+    void operator()(QObject *object) const {
+        if (object)
+            object->deleteLater();
+    }
+};
+
+} // detail
+
+/**
+ * Unique pointer for QObjects with deferred deletion
+ *
+ * @tparam T Type derived from QObject
+ */
+template<typename T>
+using DeferredUniquePtr = std::unique_ptr<T, detail::DeferredDeleter>;
+
+
+/**
+ * Helper function for creating a DeferredUniquePtr
+ *
+ * An instance of T is created and returned in a DeferredUniquePtr, such that it will be deleted via
+ * QObject::deleteLater().
+ *
+ * @tparam T       The type to create
+ * @tparam Args    Constructor argument types
+ * @param[in] args Constructor arguments
+ * @returns A DeferredUniquePtr holding a new instance of T
+ */
+template<typename T, typename ...Args>
+DeferredUniquePtr<T> makeDeferredUnique(Args... args)
+{
+    static_assert(std::is_base_of<QObject, T>::value, "Type must inherit from QObject");
+    return DeferredUniquePtr<T>(new T(std::forward<Args>(args)...));
+}
+
+
+/**
+ * Shared pointer for QObjects with deferred deletion
+ *
+ * @tparam T Type derived from QObject
+ */
+template<typename T>
+using DeferredSharedPtr = std::shared_ptr<T>;
+
+
+/**
+ * Helper function for creating a DeferredSharedPtr
+ *
+ * An instance of T is created and returned in a DeferredSharedPtr, such that it will be deleted via
+ * QObject::deleteLater().
+ *
+ * @tparam T       The type to create
+ * @tparam Args    Constructor argument types
+ * @param[in] args Constructor arguments
+ * @returns A DeferredSharedPtr holding a new instance of T
+ */
+template<typename T, typename ...Args>
+DeferredSharedPtr<T> makeDeferredShared(Args... args)
+{
+    static_assert(std::is_base_of<QObject, T>::value, "Type must inherit from QObject");
+    return DeferredSharedPtr<T>(new T(std::forward<Args>(args)...), detail::DeferredDeleter{});
+}