Improve Python docs on memory management and member variables

This commit is contained in:
William S Fulton 2019-01-09 18:24:36 +00:00
commit 2315ed878b
2 changed files with 64 additions and 26 deletions

View file

@ -1671,6 +1671,7 @@
<li><a href="Python.html#Python_nn62">Mapping Python tuples into small arrays</a> <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_nn63">Mapping sequences to C arrays</a>
<li><a href="Python.html#Python_nn64">Pointer handling</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> </ul>
<li><a href="Python.html#Python_nn65">Docstring Features</a> <li><a href="Python.html#Python_nn65">Docstring Features</a>
<ul> <ul>

View file

@ -5435,7 +5435,7 @@ that has a <tt>this</tt> attribute. In addition,
class object (if applicable). class object (if applicable).
</p> </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> <p>
@ -5449,9 +5449,11 @@ Consider the following C++ code:
<div class="code"> <div class="code">
<pre> <pre>
#include &lt;iostream&gt;
struct Wheel { struct Wheel {
int size; int size;
Wheel(int sz) : size(sz) {} Wheel(int sz) : size(sz) {}
~Wheel() { std::cout &lt;&lt; "~Wheel" &lt;&lt; std::endl; }
}; };
class Bike { class Bike {
@ -5486,6 +5488,7 @@ Don't be surprised that if the resulting output gives strange results such as...
<div class="shell"> <div class="shell">
<pre> <pre>
wheel size: 10 wheel size: 10
~Wheel
wheel size: 135019664 wheel size: 135019664
</pre> </pre>
</div> </div>
@ -5499,66 +5502,100 @@ be added to the <tt>wheel</tt> instance.
<p> <p>
You can do this by adding the reference when the <tt>getWheel()</tt> method 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>
<p> <p>
The easier, but less optimized, way is to use the typemap-like <tt>%pythonappend</tt> directive The easier, but less optimized, way is to use the <tt>%pythonappend</tt> directive
(see <a href="#Python_nn42">36.6.2 Adding additional Python code</a>): (see <a href="#Python_nn42">Adding additional Python code</a>):
</p> </p>
<div class="code"> <div class="code">
<pre> <pre>
%pythonappend getWheel %{ %pythonappend getWheel %{
# val is the Wheel proxy, self is the Bike instance # val is the Wheel proxy, self is the Bike instance
val._bike = self val.__bike_reference = self
%} %}
</pre> </pre>
</div> </div>
<p> <p>
The code gets appended to the Python code generated for the 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 instance onto the <tt>Wheel</tt> proxy instance before it is returned to the
caller. caller as follows.
</p> </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> <p>
The second option, which performs better and is required if you use the 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: <tt>-builtin</tt> option, is to set the reference in the CPython implementation:
<div class="code"> <div class="code">
<pre> <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&amp; 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>
static PyObject *extra_reference() { <p>
static PyObject *extra_reference_string = NULL; The third approach, shown below, is an optimization of the above approach and creates the "__bike_reference" Python string object just once.
if (!extra_reference_string) While this looks more complex, it is just a small variation on the above typemap plus a support function
extra_reference_string = SWIG_Python_str_FromChar("_extra_reference"); <tt>bike_reference()</tt> in a fragment called <tt>bike_reference_function</tt>.
return extra_reference_string; 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 *bike_reference() {
static PyObject *bike_reference_string = SWIG_Python_str_FromChar("__bike_reference");
return bike_reference_string;
} }
} }
%extend Wheel { %extend Wheel {
%typemap(ret, fragment="extra_reference") Wheel& getWheel %{
// A reference to the parent class is added to ensure the underlying C++ // A reference to the parent class is added to ensure the underlying C++
// object is not deleted while the item is in use // object is not deleted while the item is in use
PyObject_SetAttr($result, extra_reference(), $self); %typemap(ret, fragment="bike_reference_function") Wheel&amp; 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> </pre>
</div> </div>
<H2><a name="Python_nn65">38.10 Docstring Features</a></H2> <H2><a name="Python_nn65">38.10 Docstring Features</a></H2>