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 @@
@@ -5449,9 +5449,11 @@ Consider the following C++ code:
+#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))
wheel size: 10 +~Wheel wheel size: 135019664
You can do this by adding the reference when the getWheel() method -is called using one of two approaches: +is called using one of three approaches:
-The easier, but less optimized, way is to use the typemap-like %pythonappend directive -(see 36.6.2 Adding additional Python code): +The easier, but less optimized, way is to use the %pythonappend directive +(see Adding additional Python code):
%pythonappend getWheel %{
# val is the Wheel proxy, self is the Bike instance
- val._bike = self
+ val.__bike_reference = self
%}
The code gets appended to the Python code generated for the -Bike::getWheel function, where we store the Bike proxy +Bike::getWheel wrapper function, where we store the Bike proxy instance onto the Wheel proxy instance before it is returned to the -caller. +caller as follows.
++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 ++
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") {
+%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);
+}
+}
+
++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 +bike_reference() in a fragment called bike_reference_function. +The bike_reference_init typemap generates code into the "init" section for an initial call to bike_reference() when the module +is initialized and is done to create the "__bike_reference" Python string singleton in a thread-safe manner. +
+ +
+%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 {
-%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);
-%}
-*/
}