diff options
author | William S Fulton <wsf@fultondesigns.co.uk> | 2019-01-08 21:34:27 +0000 |
---|---|---|
committer | William S Fulton <wsf@fultondesigns.co.uk> | 2019-01-08 21:34:27 +0000 |
commit | c2e811c12da35bef5d6089269e4d09d598335740 (patch) | |
tree | 8940f78198de4488d4f82ec1f0f8fa0b7efafe84 /Doc | |
parent | 4e4bb54fe7f01432825a1e0bcc1ffde7bd822271 (diff) | |
parent | 26e08be7ce465799ad9f40f2e0781b4780581454 (diff) | |
download | swig-c2e811c12da35bef5d6089269e4d09d598335740.tar.gz |
Merge branch 'jakecobb-python-memory-docs'
* jakecobb-python-memory-docs:
-builtin compatible ref example in Python docs
%pythonappend docs and memory management example
Diffstat (limited to 'Doc')
-rw-r--r-- | Doc/Manual/Python.html | 125 |
1 files changed, 125 insertions, 0 deletions
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 @@ <li><a href="#Python_nn62">Mapping Python tuples into small arrays</a> <li><a href="#Python_nn63">Mapping sequences to C arrays</a> <li><a href="#Python_nn64">Pointer handling</a> +<li><a href="#Python_memory_management_member_variables">Memory management when returning references to member variables</a> </ul> <li><a href="#Python_nn65">Docstring Features</a> <ul> @@ -3572,6 +3573,7 @@ proxy, just before the return statement. %feature("pythonappend") Foo::bar(int) %{ #do something after C++ call + #the 'val' variable holds the return value %} @@ -3601,6 +3603,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 %} @@ -5432,6 +5435,128 @@ that has a <tt>this</tt> attribute. In addition, class object (if applicable). </p> +<H3><a name="Python_memory_management_member_variables">36.9.7 Memory management when returning references to member variables</a></H3> + + +<p> +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 <a href="Java.html#Java_memory_management_objects">Java equivalent</a>. +</p> + +<p> +Consider the following C++ code: +</p> + +<div class="code"> +<pre> +struct Wheel { + int size; + Wheel(int sz) : size(sz) {} +}; + +class Bike { + Wheel wheel; +public: + Bike(int val) : wheel(val) {} + Wheel& getWheel() { return wheel; } +}; +</pre> +</div> + +<p> +and the following usage from Python after running the code through SWIG: +</p> + + +<div class="code"> +<pre> +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)) +</pre> +</div> + +<p> +Don't be surprised that if the resulting output gives strange results such as... +</p> + +<div class="shell"> +<pre> +wheel size: 10 +wheel size: 135019664 +</pre> +</div> + +<p> +What has happened here is the garbage collector has collected the <tt>Bike</tt> instance as it doesn't think it is needed any more. +The proxy instance, <tt>wheel</tt>, contains a reference to memory that was deleted when the <tt>Bike</tt> instance was collected. +In order to prevent the garbage collector from collecting the <tt>Bike</tt> instance, a reference to the <tt>Bike</tt> must +be added to the <tt>wheel</tt> instance. +</p> + +<p> +You can do this by adding the reference when the <tt>getWheel()</tt> method +is called using one of two approaches: +</p> + +<p> +The easier, but less optimized, way is to use the typemap-like <tt>%pythonappend</tt> directive +(see <a href="#Python_nn42">36.6.2 Adding additional Python code</a>): +</p> + +<div class="code"> +<pre> +%pythonappend getWheel %{ + # val is the Wheel proxy, self is the Bike instance + val._bike = self +%} +</pre> +</div> + +<p> +The code gets appended to the Python code generated for the +<tt>Bike::getWheel</tt> function, where we store the <tt>Bike</tt> proxy +instance onto the <tt>Wheel</tt> proxy instance before it is returned to the +caller. +</p> + +<p> +The second option, which performs better and is required if you use the +<tt>-builtin</tt> option, is to set the reference in the CPython implementation: + +<div class="code"> +<pre> +%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); +%} +*/ +} +</pre> +</div> <H2><a name="Python_nn65">38.10 Docstring Features</a></H2> |