diff options
author | William S Fulton <wsf@fultondesigns.co.uk> | 2019-01-09 18:24:36 +0000 |
---|---|---|
committer | William S Fulton <wsf@fultondesigns.co.uk> | 2019-01-09 18:24:36 +0000 |
commit | 2315ed878b0cdac1d47853a7c526cacf2a83c23f (patch) | |
tree | f594fec5d1ba5c524729354b4f8edec62833629b /Doc | |
parent | c2e811c12da35bef5d6089269e4d09d598335740 (diff) | |
download | swig-2315ed878b0cdac1d47853a7c526cacf2a83c23f.tar.gz |
Improve Python docs on memory management and member variables
Diffstat (limited to 'Doc')
-rw-r--r-- | Doc/Manual/Contents.html | 1 | ||||
-rw-r--r-- | Doc/Manual/Python.html | 89 |
2 files changed, 64 insertions, 26 deletions
diff --git a/Doc/Manual/Contents.html b/Doc/Manual/Contents.html index d9bc4bc05..f8a731fe2 100644 --- a/Doc/Manual/Contents.html +++ b/Doc/Manual/Contents.html @@ -1671,6 +1671,7 @@ <li><a href="Python.html#Python_nn62">Mapping Python tuples into small arrays</a> <li><a href="Python.html#Python_nn63">Mapping sequences to C arrays</a> <li><a href="Python.html#Python_nn64">Pointer handling</a> +<li><a href="Python.html#Python_memory_management_member_variables">Memory management when returning references to member variables</a> </ul> <li><a href="Python.html#Python_nn65">Docstring Features</a> <ul> diff --git a/Doc/Manual/Python.html b/Doc/Manual/Python.html index 6f8e1ddfa..e94d9d9cb 100644 --- a/Doc/Manual/Python.html +++ b/Doc/Manual/Python.html @@ -5435,7 +5435,7 @@ 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> +<H3><a name="Python_memory_management_member_variables">38.9.7 Memory management when returning references to member variables</a></H3> <p> @@ -5449,9 +5449,11 @@ Consider the following C++ code: <div class="code"> <pre> +#include <iostream> struct Wheel { int size; Wheel(int sz) : size(sz) {} + ~Wheel() { std::cout << "~Wheel" << std::endl; } }; class Bike { @@ -5474,7 +5476,7 @@ bike = Bike(10) wheel = bike.getWheel() print("wheel size: {}".format(wheel.size)) -del bike # Allow bike to be garbage collected +del bike # Allow bike to be garbage collected print("wheel size: {}".format(wheel.size)) </pre> </div> @@ -5486,6 +5488,7 @@ Don't be surprised that if the resulting output gives strange results such as... <div class="shell"> <pre> wheel size: 10 +~Wheel wheel size: 135019664 </pre> </div> @@ -5499,66 +5502,100 @@ be added to the <tt>wheel</tt> instance. <p> You can do this by adding the reference when the <tt>getWheel()</tt> method -is called using one of two approaches: +is called using one of three 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>): +The easier, but less optimized, way is to use the <tt>%pythonappend</tt> directive +(see <a href="#Python_nn42">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 + val.__bike_reference = 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 +<tt>Bike::getWheel</tt> wrapper function, where we store the <tt>Bike</tt> proxy instance onto the <tt>Wheel</tt> proxy instance before it is returned to the -caller. +caller as follows. </p> +<div class="targetlang"> +<pre> +class Bike(object): + ... + def getWheel(self): + val = _example.Bike_getWheel(self) + + # val is the Wheel proxy, self is the Bike instance + val.__bike_reference = self + + return val +</pre> +</div> + + <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") { +%extend Wheel { +// A reference to the parent class is added to ensure the underlying C++ +// object is not deleted while the item is in use +%typemap(ret) Wheel& getWheel { + PyObject *bike_reference_string = SWIG_Python_str_FromChar("__bike_reference"); + PyObject_SetAttr($result, bike_reference_string, $self); + Py_DecRef(bike_reference_string); +} +} +</pre> +</div> + +<p> +The third approach, shown below, is an optimization of the above approach and creates the "__bike_reference" Python string object just once. +While this looks more complex, it is just a small variation on the above typemap plus a support function +<tt>bike_reference()</tt> in a fragment called <tt>bike_reference_function</tt>. +The <tt>bike_reference_init</tt> typemap generates code into the "init" section for an initial call to <tt>bike_reference()</tt> when the module +is initialized and is done to create the "__bike_reference" Python string singleton in a thread-safe manner. +</p> + +<div class="code"> +<pre> +%fragment("bike_reference_init", "init") { + // Thread-safe initialization - initialize during Python module initialization + bike_reference(); +} + +%fragment("bike_reference_function", "header", fragment="bike_reference_init") { -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; +static PyObject *bike_reference() { + static PyObject *bike_reference_string = SWIG_Python_str_FromChar("__bike_reference"); + return bike_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); +// A reference to the parent class is added to ensure the underlying C++ +// object is not deleted while the item is in use +%typemap(ret, fragment="bike_reference_function") Wheel& getWheel %{ + PyObject_SetAttr($result, bike_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> |