Browse Source

Make a Releasable class for the smart pointer deleters, to aid in correct new/delete across libraries.

Michael Ragazzon 6 years ago
parent
commit
39318abafa

+ 3 - 1
Include/RmlUi/Core/Element.h

@@ -71,7 +71,7 @@ struct ElementMeta;
 	@author Peter Curry
  */
 
-class RMLUICORE_API Element : public NonCopyMoveable
+class RMLUICORE_API Element : public Releasable
 {
 public:
 	/// Constructs a new RmlUi element. This should not be called directly; use the Factory
@@ -615,6 +615,8 @@ protected:
 
 	void SetOwnerDocument(ElementDocument* document);
 
+	void Release() override;
+
 private:
 	void SetParent(Element* parent);
 

+ 1 - 1
Include/RmlUi/Core/ElementInstancer.h

@@ -52,7 +52,7 @@ class Element;
 	@author Lloyd Weehuizen
  */ 
 
-class RMLUICORE_API ElementInstancer : public NonCopyMoveable
+class RMLUICORE_API ElementInstancer : public Releasable
 {
 public:
 	virtual ~ElementInstancer();

+ 3 - 0
Include/RmlUi/Core/ElementInstancerGeneric.h

@@ -57,6 +57,9 @@ public:
 	/// Releases the given element
 	/// @param element to release
 	void ReleaseElement(Element* element) override;
+
+	/// Release the instancer
+	void Release() override;
 };
 
 }

+ 8 - 0
Include/RmlUi/Core/ElementInstancerGeneric.inl

@@ -50,5 +50,13 @@ void ElementInstancerGeneric<T>::ReleaseElement(Element* element)
 	delete element;
 }
 
+
+// Release the instancer
+template <typename T>
+void ElementInstancerGeneric<T>::Release()
+{
+	delete this;
+}
+
 }
 }

+ 28 - 1
Include/RmlUi/Core/ReferenceCountable.h

@@ -35,7 +35,7 @@ namespace Rml {
 namespace Core {
 
 
-class NonCopyMoveable {
+class RMLUICORE_API NonCopyMoveable {
 public:
 	NonCopyMoveable() {}
 	~NonCopyMoveable() {}
@@ -45,6 +45,33 @@ public:
 	NonCopyMoveable& operator=(NonCopyMoveable&&) = delete;
 };
 
+
+class ReleaserBase;
+
+class RMLUICORE_API Releasable : public NonCopyMoveable {
+protected:
+	virtual void Release() = 0;
+	friend class ReleaserBase;
+};
+
+class RMLUICORE_API ReleaserBase {
+protected:
+	void Release(Releasable* target) const {
+		target->Release();
+	}
+};
+
+template<typename T>
+class RMLUICORE_API Releaser final : public ReleaserBase {
+public:
+	void operator()(T* target) const {
+		Release(static_cast<Releasable*>(target));
+	}
+};
+
+
+
+
 /**
 	A base class for any class that wishes to be reference counted.
 	@author Robert Curry

+ 3 - 2
Include/RmlUi/Core/Types.h

@@ -48,6 +48,7 @@
 
 #include "Platform.h"
 #include "Debug.h"
+#include "ReferenceCountable.h"
 
 #ifdef RMLUI_DEBUG
 #include <unordered_map>
@@ -99,8 +100,8 @@ typedef ColumnMajorMatrix4f Matrix4f;
 
 class Element;
 class ElementInstancer;
-using ElementPtr = std::unique_ptr<Element>;
-using ElementInstancerPtr = std::unique_ptr<ElementInstancer>;
+using ElementPtr = std::unique_ptr<Element, Releaser<Element>>;
+using ElementInstancerPtr = std::unique_ptr<ElementInstancer, Releaser<ElementInstancer>>;
 class ElementAnimation;
 class Property;
 class Variant;

+ 1 - 1
Samples/invaders/src/main.cpp

@@ -121,7 +121,7 @@ int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
 	Shell::LoadFonts("assets/");
 
 	// Register Invader's custom element and decorator instancers.
-	Rml::Core::Factory::RegisterElementInstancer("game", std::make_unique<Rml::Core::ElementInstancerGeneric< ElementGame >>());
+	Rml::Core::Factory::RegisterElementInstancer("game", Rml::Core::ElementInstancerPtr(new Rml::Core::ElementInstancerGeneric< ElementGame >));
 
 	Rml::Core::Factory::RegisterDecoratorInstancer("starfield", std::make_unique<DecoratorInstancerStarfield>());
 	Rml::Core::Factory::RegisterDecoratorInstancer("defender", std::make_unique<DecoratorInstancerDefender>());

+ 11 - 11
Source/Controls/Controls.cpp

@@ -45,27 +45,27 @@ namespace Controls {
 // Registers the custom element instancers.
 void RegisterElementInstancers()
 {
-	Core::Factory::RegisterElementInstancer("form", std::make_unique<Core::ElementInstancerGeneric< ElementForm >>());
+	Core::Factory::RegisterElementInstancer("form", Core::ElementInstancerPtr(new Core::ElementInstancerGeneric< ElementForm >));
 
-	Core::Factory::RegisterElementInstancer("input", std::make_unique<Core::ElementInstancerGeneric< ElementFormControlInput >>());
+	Core::Factory::RegisterElementInstancer("input", Core::ElementInstancerPtr(new Core::ElementInstancerGeneric< ElementFormControlInput >));
 
-	Core::Factory::RegisterElementInstancer("dataselect", std::make_unique<Core::ElementInstancerGeneric< ElementFormControlDataSelect >>());
+	Core::Factory::RegisterElementInstancer("dataselect", Core::ElementInstancerPtr(new Core::ElementInstancerGeneric< ElementFormControlDataSelect >));
 
-	Core::Factory::RegisterElementInstancer("select", std::make_unique<Core::ElementInstancerGeneric< ElementFormControlSelect >>());
+	Core::Factory::RegisterElementInstancer("select", Core::ElementInstancerPtr(new Core::ElementInstancerGeneric< ElementFormControlSelect >));
 
-	Core::Factory::RegisterElementInstancer("textarea", std::make_unique<Core::ElementInstancerGeneric< ElementFormControlTextArea >>());
+	Core::Factory::RegisterElementInstancer("textarea", Core::ElementInstancerPtr(new Core::ElementInstancerGeneric< ElementFormControlTextArea >));
 
-	Core::Factory::RegisterElementInstancer("#selection", std::make_unique<Core::ElementInstancerGeneric< ElementTextSelection >>());
+	Core::Factory::RegisterElementInstancer("#selection", Core::ElementInstancerPtr(new Core::ElementInstancerGeneric< ElementTextSelection >));
 
-	Core::Factory::RegisterElementInstancer("tabset", std::make_unique<Core::ElementInstancerGeneric< ElementTabSet >>());
+	Core::Factory::RegisterElementInstancer("tabset", Core::ElementInstancerPtr(new Core::ElementInstancerGeneric< ElementTabSet >));
 
-	Core::Factory::RegisterElementInstancer("datagrid", std::make_unique<Core::ElementInstancerGeneric< ElementDataGrid >>());
+	Core::Factory::RegisterElementInstancer("datagrid", Core::ElementInstancerPtr(new Core::ElementInstancerGeneric< ElementDataGrid >));
 
-	Core::Factory::RegisterElementInstancer("datagridexpand", std::make_unique<Core::ElementInstancerGeneric< ElementDataGridExpandButton >>());
+	Core::Factory::RegisterElementInstancer("datagridexpand", Core::ElementInstancerPtr(new Core::ElementInstancerGeneric< ElementDataGridExpandButton >));
 
-	Core::Factory::RegisterElementInstancer("#rmlctl_datagridcell", std::make_unique<Core::ElementInstancerGeneric< ElementDataGridCell >>());
+	Core::Factory::RegisterElementInstancer("#rmlctl_datagridcell", Core::ElementInstancerPtr(new Core::ElementInstancerGeneric< ElementDataGridCell >));
 
-	Core::Factory::RegisterElementInstancer("#rmlctl_datagridrow", std::make_unique<Core::ElementInstancerGeneric< ElementDataGridRow >>());
+	Core::Factory::RegisterElementInstancer("#rmlctl_datagridrow", Core::ElementInstancerPtr(new Core::ElementInstancerGeneric< ElementDataGridRow >));
 }
 
 void RegisterXMLNodeHandlers()

+ 8 - 0
Source/Core/Element.cpp

@@ -2110,6 +2110,14 @@ void Element::SetOwnerDocument(ElementDocument* document)
 	}
 }
 
+void Element::Release()
+{
+	if (instancer)
+		instancer->ReleaseElement(this);
+	else
+		Log::Message(Log::LT_WARNING, "Leak detected: element %s not instanced via RmlUi Factory. Unable to release.", GetAddress().c_str());
+}
+
 void Element::SetParent(Element* _parent)
 {	
 	// If there's an old parent, detach from it first.

+ 5 - 5
Source/Core/Factory.cpp

@@ -98,11 +98,11 @@ bool Factory::Initialise()
 		event_listener_instancer = NULL;
 
 	// Bind the default element instancers
-	RegisterElementInstancer("*", std::make_unique<ElementInstancerGeneric< Element >>());
-	RegisterElementInstancer("img", std::make_unique < ElementInstancerGeneric< ElementImage >>());
-	RegisterElementInstancer("#text", std::make_unique < ElementInstancerGeneric< ElementTextDefault >>());
-	RegisterElementInstancer("handle", std::make_unique < ElementInstancerGeneric< ElementHandle >>());
-	RegisterElementInstancer("body", std::make_unique < ElementInstancerGeneric< ElementDocument >>());
+	RegisterElementInstancer("*", ElementInstancerPtr(new ElementInstancerGeneric< Element >));
+	RegisterElementInstancer("img", ElementInstancerPtr(new ElementInstancerGeneric< ElementImage >));
+	RegisterElementInstancer("#text", ElementInstancerPtr(new ElementInstancerGeneric< ElementTextDefault >));
+	RegisterElementInstancer("handle", ElementInstancerPtr(new ElementInstancerGeneric< ElementHandle >));
+	RegisterElementInstancer("body", ElementInstancerPtr(new ElementInstancerGeneric< ElementDocument >));
 
 	// Bind the default decorator instancers
 	RegisterDecoratorInstancer("tiled-horizontal", std::make_unique<DecoratorTiledHorizontalInstancer>());

+ 3 - 3
Source/Debugger/Plugin.cpp

@@ -83,7 +83,7 @@ bool Plugin::Initialise(Core::Context* context)
 		return false;
 	}
 
-	Core::Factory::RegisterElementInstancer("debug-hook", std::make_unique<Core::ElementInstancerGeneric< ElementContextHook >>());
+	Core::Factory::RegisterElementInstancer("debug-hook", Core::ElementInstancerPtr(new Core::ElementInstancerGeneric< ElementContextHook >));
 
 	return true;
 }
@@ -336,7 +336,7 @@ bool Plugin::LoadMenuElement()
 
 bool Plugin::LoadInfoElement()
 {
-	Core::Factory::RegisterElementInstancer("debug-info", std::make_unique<Core::ElementInstancerGeneric< ElementInfo >>());
+	Core::Factory::RegisterElementInstancer("debug-info", Core::ElementInstancerPtr(new Core::ElementInstancerGeneric< ElementInfo >));
 	info_element = dynamic_cast< ElementInfo* >(host_context->CreateDocument("debug-info"));
 	if (info_element == NULL)
 		return false;
@@ -356,7 +356,7 @@ bool Plugin::LoadInfoElement()
 
 bool Plugin::LoadLogElement()
 {
-	Core::Factory::RegisterElementInstancer("debug-log", std::make_unique<Core::ElementInstancerGeneric< ElementLog >>());
+	Core::Factory::RegisterElementInstancer("debug-log", Core::ElementInstancerPtr(new Core::ElementInstancerGeneric< ElementLog >));
 	log_element = dynamic_cast< ElementLog* >(host_context->CreateDocument("debug-log"));
 	if (log_element == NULL)
 		return false;