Merge branch 'jakecobb-python-memory-docs'
* jakecobb-python-memory-docs: -builtin compatible ref example in Python docs %pythonappend docs and memory management example
This commit is contained in:
commit
c2e811c12d
1 changed files with 125 additions and 0 deletions
|
|
@ -100,6 +100,7 @@
|
||||||
<li><a href="#Python_nn62">Mapping Python tuples into small arrays</a>
|
<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_nn63">Mapping sequences to C arrays</a>
|
||||||
<li><a href="#Python_nn64">Pointer handling</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>
|
</ul>
|
||||||
<li><a href="#Python_nn65">Docstring Features</a>
|
<li><a href="#Python_nn65">Docstring Features</a>
|
||||||
<ul>
|
<ul>
|
||||||
|
|
@ -3572,6 +3573,7 @@ proxy, just before the return statement.
|
||||||
|
|
||||||
%feature("pythonappend") Foo::bar(int) %{
|
%feature("pythonappend") Foo::bar(int) %{
|
||||||
#do something after C++ call
|
#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) %{
|
%pythonappend Foo::bar(int) %{
|
||||||
#do something after C++ call
|
#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).
|
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>
|
||||||
|
|
||||||
|
|
||||||
|
<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>
|
<H2><a name="Python_nn65">38.10 Docstring Features</a></H2>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue