diff --git a/Doc/Manual/Python.html b/Doc/Manual/Python.html index 8d1678a7f..6f8e1ddfa 100644 --- a/Doc/Manual/Python.html +++ b/Doc/Manual/Python.html @@ -100,6 +100,7 @@
+This example shows how to prevent premature garbage collection of objects when the underlying C++ class returns a pointer or reference to a member variable. +The example is a direct equivalent to this Java equivalent. +
+ ++Consider the following C++ code: +
+ +
+struct Wheel {
+ int size;
+ Wheel(int sz) : size(sz) {}
+};
+
+class Bike {
+ Wheel wheel;
+public:
+ Bike(int val) : wheel(val) {}
+ Wheel& getWheel() { return wheel; }
+};
+
++and the following usage from Python after running the code through SWIG: +
+ + +
+bike = Bike(10)
+wheel = bike.getWheel()
+print("wheel size: {}".format(wheel.size))
+
+del bike # Allow bike to be garbage collected
+print("wheel size: {}".format(wheel.size))
+
++Don't be surprised that if the resulting output gives strange results such as... +
+ ++wheel size: 10 +wheel size: 135019664 ++
+What has happened here is the garbage collector has collected the Bike instance as it doesn't think it is needed any more. +The proxy instance, wheel, contains a reference to memory that was deleted when the Bike instance was collected. +In order to prevent the garbage collector from collecting the Bike instance, a reference to the Bike must +be added to the wheel instance. +
+ ++You can do this by adding the reference when the getWheel() method +is called using one of two approaches: +
+ ++The easier, but less optimized, way is to use the typemap-like %pythonappend directive +(see 36.6.2 Adding additional Python code): +
+ +
+%pythonappend getWheel %{
+ # val is the Wheel proxy, self is the Bike instance
+ val._bike = self
+%}
+
++The code gets appended to the Python code generated for the +Bike::getWheel function, where we store the Bike proxy +instance onto the Wheel proxy instance before it is returned to the +caller. +
+ ++The second option, which performs better and is required if you use the +-builtin option, is to set the reference in the CPython implementation: + +
+%fragment("extra_reference", "header") {
+
+static PyObject *extra_reference() {
+ static PyObject *extra_reference_string = NULL;
+ if (!extra_reference_string)
+ extra_reference_string = SWIG_Python_str_FromChar("_extra_reference");
+ return extra_reference_string;
+}
+
+}
+
+%extend Wheel {
+%typemap(ret, fragment="extra_reference") Wheel& getWheel %{
+ // A reference to the parent class is added to ensure the underlying C++
+ // object is not deleted while the item is in use
+ PyObject_SetAttr($result, extra_reference(), $self);
+%}
+/* FYI: Alternative approach, but is possibly harder to understand, so suggest above
+%typemap(out, fragment="extra_reference") Wheel& getWheel %{
+ $typemap(out, Wheel &)
+ // A reference to the parent class is added to ensure the underlying C++
+ // object is not deleted while the item is in use
+ PyObject_SetAttr($result, extra_reference(), $self);
+%}
+*/
+}
+
+