From 4ae4fe8a42597848b9759a4b0e7662deb76c382e Mon Sep 17 00:00:00 2001
From: Jake Cobb
@@ -3543,6 +3544,7 @@ proxy, just before the return statement.
%feature("pythonappend") Foo::bar(int) %{
#do something after C++ call
+ #the 'val' variable holds the return value
%}
@@ -3572,6 +3574,7 @@ SWIG version 1.3.28 you can use the directive forms
%pythonappend Foo::bar(int) %{
#do something after C++ call
+ #the 'val' variable holds the return value
%}
@@ -5267,6 +5270,85 @@ that has a this attribute. In addition,
class object (if applicable).
+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 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. +
+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):
-@@ -5349,6 +5357,41 @@ The code gets appended to the Python code generated for the 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); +%} +*/ +} ++36.10 Docstring Features