nicer code separation, cleanup logic, std::function type caster
diff --git a/include/pybind/pybind.h b/include/pybind/pybind.h
index 64ae5a0..de496fb 100644
--- a/include/pybind/pybind.h
+++ b/include/pybind/pybind.h
@@ -16,9 +16,15 @@
 #pragma warning(disable: 4996) // warning C4996: The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name
 #pragma warning(disable: 4100) // warning C4100: Unreferenced formal parameter
 #pragma warning(disable: 4512) // warning C4512: Assignment operator was implicitly defined as deleted
+#elif defined(__GNUG__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
+#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
 #endif
 
 #include <pybind/cast.h>
+#include <iostream>
 
 NAMESPACE_BEGIN(pybind)
 
@@ -57,7 +63,8 @@
     struct function_entry {
         const char *name = nullptr;
         PyObject * (*impl) (function_entry *, PyObject *, PyObject *, PyObject *);
-        void *data;
+        PyMethodDef *def;
+        void *data = nullptr;
         bool is_constructor = false, is_method = false;
         short keywords = 0;
         return_value_policy policy = return_value_policy::automatic;
@@ -304,6 +311,17 @@
         }
     }
 
+    static void destruct(function_entry *entry) {
+        while (entry) {
+            delete entry->def;
+            operator delete(entry->data);
+            Py_XDECREF(entry->sibling);
+            function_entry *next = entry->next;
+            delete entry;
+            entry = next;
+        }
+    }
+
     void initialize(function_entry *entry, int args) {
         if (entry->name == nullptr)
             entry->name = "";
@@ -316,13 +334,13 @@
         entry->is_constructor = !strcmp(entry->name, "__init__");
 
         if (!entry->sibling || !PyCFunction_Check(entry->sibling)) {
-            PyMethodDef *def = new PyMethodDef();
-            memset(def, 0, sizeof(PyMethodDef));
-            def->ml_name = entry->name;
-            def->ml_meth = reinterpret_cast<PyCFunction>(*dispatcher);
-            def->ml_flags = METH_VARARGS | METH_KEYWORDS;
-            capsule entry_capsule(entry);
-            m_ptr = PyCFunction_New(def, entry_capsule.ptr());
+            entry->def = new PyMethodDef();
+            memset(entry->def, 0, sizeof(PyMethodDef));
+            entry->def->ml_name = entry->name;
+            entry->def->ml_meth = reinterpret_cast<PyCFunction>(*dispatcher);
+            entry->def->ml_flags = METH_VARARGS | METH_KEYWORDS;
+            capsule entry_capsule(entry, [](PyObject *o) { destruct((function_entry *) PyCapsule_GetPointer(o, nullptr)); });
+            m_ptr = PyCFunction_New(entry->def, entry_capsule.ptr());
             if (!m_ptr)
                 throw std::runtime_error("cpp_function::cpp_function(): Could not allocate function object");
         } else {
@@ -335,6 +353,7 @@
             parent->next = entry;
             entry = backup;
         }
+
         std::string signatures;
         int index = 0;
         function_entry *it = entry;
@@ -799,4 +818,7 @@
 
 #if defined(_MSC_VER)
 #pragma warning(pop)
+#elif defined(__GNUG__)
+#pragma GCC diagnostic pop
 #endif
+