Fix %newobject when used in conjunction with %feature(ref). The code from the ref feature was not always being generated for the function specified by %newobject. Documentation for ref and unref moved from Python to the C++ chapter.
git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@12783 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
parent
86e1051a8b
commit
c794d08597
8 changed files with 262 additions and 160 deletions
|
|
@ -4618,6 +4618,180 @@ p = f.__deref__() # Raw pointer from operator->
|
|||
<b>Note:</b> Smart pointer support was first added in SWIG-1.3.14.
|
||||
</p>
|
||||
|
||||
<H2><a name="SWIGPlus_ref_unref"></a>C++ reference counted objects - ref/unref feature</H2>
|
||||
|
||||
|
||||
<p>
|
||||
Another similar idiom in C++ is the use of reference counted objects. Consider for example:
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
class RCObj {
|
||||
// implement the ref counting mechanism
|
||||
int add_ref();
|
||||
int del_ref();
|
||||
int ref_count();
|
||||
|
||||
public:
|
||||
virtual ~RCObj() = 0;
|
||||
|
||||
int ref() const {
|
||||
return add_ref();
|
||||
}
|
||||
|
||||
int unref() const {
|
||||
if (ref_count() == 0 || del_ref() == 0 ) {
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
return ref_count();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class A : RCObj {
|
||||
public:
|
||||
A();
|
||||
int foo();
|
||||
};
|
||||
|
||||
|
||||
class B {
|
||||
A *_a;
|
||||
|
||||
public:
|
||||
B(A *a) : _a(a) {
|
||||
a->ref();
|
||||
}
|
||||
|
||||
~B() {
|
||||
a->unref();
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
A *a = new A(); // (count: 0)
|
||||
a->ref(); // 'a' ref here (count: 1)
|
||||
|
||||
B *b1 = new B(a); // 'a' ref here (count: 2)
|
||||
if (1 + 1 == 2) {
|
||||
B *b2 = new B(a); // 'a' ref here (count: 3)
|
||||
delete b2; // 'a' unref, but not deleted (count: 2)
|
||||
}
|
||||
|
||||
delete b1; // 'a' unref, but not deleted (count: 1)
|
||||
a->unref(); // 'a' unref and deleted (count: 0)
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
In the example above, the 'A' class instance 'a' is a reference counted
|
||||
object, which can't be deleted arbitrarily since it is shared between
|
||||
the objects 'b1' and 'b2'. 'A' is derived from a <i>Reference Counted
|
||||
Object</i> 'RCObj', which implements the ref/unref idiom.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To tell SWIG that 'RCObj' and all its derived classes are reference
|
||||
counted objects, use the "ref" and "unref" <a href="Customization.html#Customization_features">features</a>.
|
||||
These are also available as <tt>%refobject</tt> and <tt>%unrefobject</tt>, respectively.
|
||||
For example:
|
||||
</p>
|
||||
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
%module example
|
||||
...
|
||||
|
||||
%feature("ref") RCObj "$this->ref();"
|
||||
%feature("unref") RCObj "$this->unref();"
|
||||
|
||||
%include "rcobj.h"
|
||||
%include "A.h"
|
||||
...
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
where the code passed to the "ref" and "unref" features will be
|
||||
executed as needed whenever a new object is passed to python, or when
|
||||
python tries to release the proxy object instance, respectively.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
On the python side, the use of a reference counted object is no
|
||||
different to any other regular instance:
|
||||
</p>
|
||||
|
||||
<div class="targetlang">
|
||||
<pre>
|
||||
def create_A():
|
||||
a = A() # SWIG ref 'a' - new object is passed to python (count: 1)
|
||||
b1 = B(a) # C++ ref 'a (count: 2)
|
||||
if 1 + 1 == 2:
|
||||
b2 = B(a) # C++ ref 'a' (count: 3)
|
||||
return a # 'b1' and 'b2' are released and deleted, C++ unref 'a' twice (count: 1)
|
||||
|
||||
a = create_A() # (count: 1)
|
||||
exit # 'a' is released, SWIG unref 'a' called in the destructor wrapper (count: 0)
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Note that the user doesn't explicitly need to call 'a->ref()' nor 'a->unref()'
|
||||
(and neither 'delete a'). Instead, SWIG takes cares of executing the "ref"
|
||||
and "unref" calls as needed. If the user doesn't specify the
|
||||
"ref/unref" feature for a type, SWIG will produce code equivalent to defining these
|
||||
features:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
%feature("ref") ""
|
||||
%feature("unref") "delete $this;"
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
In other words, SWIG will not do anything special when a new object
|
||||
is passed to python, and it will always 'delete' the underlying object when
|
||||
python releases the proxy instance.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <a href="Customization.html#Customization_ownership">%newobject feature</a> is designed to indicate to
|
||||
the target language that it should take ownership of the returned object.
|
||||
When used in conjunction with a type that has the "ref" feature associated with it, it additionally emits the
|
||||
code in the "ref" feature into the C++ wrapper.
|
||||
Consider wrapping the following factory function in addition to the above:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
%newobject AFactory;
|
||||
A *AFactory() {
|
||||
return new A();
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
The <tt>AFactory</tt> function now acts much like a call to the <tt>A</tt> constructor with respect to memory handling:
|
||||
</p>
|
||||
|
||||
<div class="targetlang">
|
||||
<pre>
|
||||
a = AFactory() # SWIG ref 'a' due to %newobject (count: 1)
|
||||
exit # 'a' is released, SWIG unref 'a' called in the destructor wrapper (count: 0)
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<H2><a name="SWIGPlus_nn35"></a>6.25 Using declarations and inheritance</H2>
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue