Filled in missing section on proxies.
git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk/SWIG@4666 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
parent
a909372d29
commit
d14a72baba
1 changed files with 230 additions and 3 deletions
|
|
@ -222,8 +222,11 @@ static void print(List *l);
|
||||||
};
|
};
|
||||||
</pre></blockquote>
|
</pre></blockquote>
|
||||||
|
|
||||||
<a name="n7"></a><H3>5.5.1 Constructors and destructors</H3>
|
To generate wrappers for this class, SWIG first reduces the class to a collection of low-level C-style
|
||||||
|
accessor functions. The next few sections describe this process. Later parts of the chapter decribe a higher
|
||||||
|
level interface based on proxy classes.
|
||||||
|
|
||||||
|
<a name="n7"></a><H3>5.5.1 Constructors and destructors</H3>
|
||||||
|
|
||||||
C++ constructors and destructors are translated into accessor
|
C++ constructors and destructors are translated into accessor
|
||||||
functions such as the following :<p>
|
functions such as the following :<p>
|
||||||
|
|
@ -3458,8 +3461,232 @@ of your project.
|
||||||
|
|
||||||
<a name="n36"></a><H2>5.25 Proxy classes</H2>
|
<a name="n36"></a><H2>5.25 Proxy classes</H2>
|
||||||
|
|
||||||
|
In order to provide a more natural API, many of SWIG's target
|
||||||
|
languages also wrap C++ classes with special proxy classes. These
|
||||||
|
proxy classes are typically implemented in the target language itself.
|
||||||
|
For example, if you're building a Python module, each C++ class is
|
||||||
|
wrapped with Python class. Or if you're building a Java module, each
|
||||||
|
C++ class is wrapped by a Java class.
|
||||||
|
|
||||||
Write me.
|
<h3>Construction of proxy classes</h3>
|
||||||
|
|
||||||
|
Proxy classes are always constructed as an extra layer of wrapping that uses the low-level
|
||||||
|
accessor functions described in the previous section. To illustrate, suppose you had a
|
||||||
|
C++ class like this:
|
||||||
|
|
||||||
|
<blockquote>
|
||||||
|
<pre>
|
||||||
|
class Foo {
|
||||||
|
public:
|
||||||
|
Foo();
|
||||||
|
~Foo();
|
||||||
|
int bar(int x);
|
||||||
|
int x;
|
||||||
|
};
|
||||||
|
</pre>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
Using C++ as pseudocode, a proxy class looks something like this:
|
||||||
|
|
||||||
|
<blockquote>
|
||||||
|
<pre>
|
||||||
|
class FooProxy {
|
||||||
|
private:
|
||||||
|
Foo *self;
|
||||||
|
public:
|
||||||
|
FooProxy() {
|
||||||
|
self = new_Foo();
|
||||||
|
}
|
||||||
|
~FooProxy() {
|
||||||
|
delete_Foo(self);
|
||||||
|
}
|
||||||
|
int bar(int x) {
|
||||||
|
return Foo_bar(self,x);
|
||||||
|
}
|
||||||
|
int x_get() {
|
||||||
|
return Foo_x_get(self);
|
||||||
|
}
|
||||||
|
void x_set(int x) {
|
||||||
|
Foo_x_set(self,x);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</pre>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
Of course, always keep in mind that the real proxy class is written in the target language.
|
||||||
|
For example, in Python, the proxy might look roughly like this:
|
||||||
|
|
||||||
|
<blockquote>
|
||||||
|
<pre>
|
||||||
|
class Foo:
|
||||||
|
def __init__(self):
|
||||||
|
self.this = new_Foo()
|
||||||
|
def __del__(self):
|
||||||
|
delete_Foo(self.this)
|
||||||
|
def bar(self,x):
|
||||||
|
return Foo_bar(self.this,x)
|
||||||
|
def __getattr__(self,name):
|
||||||
|
if name == 'x':
|
||||||
|
return Foo_x_get(self.this)
|
||||||
|
...
|
||||||
|
def __setattr__(self,name,value):
|
||||||
|
if name == 'x':
|
||||||
|
Foo_x_set(self.this,value)
|
||||||
|
...
|
||||||
|
</pre>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
Again, it's important to emphasize that the low-level accessor functions are always used to construct the
|
||||||
|
proxy classes.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Whenever possible, proxies try to take advantage of language features that are similar to C++. This
|
||||||
|
might include operator overloading, exception handling, and other features.
|
||||||
|
|
||||||
|
<h3>Resource management in proxies</h3>
|
||||||
|
|
||||||
|
A major issue with proxies concerns the memory management of wrapped objects. Consider the following
|
||||||
|
C++ code:
|
||||||
|
|
||||||
|
<blockquote>
|
||||||
|
<pre>
|
||||||
|
class Foo {
|
||||||
|
public:
|
||||||
|
Foo();
|
||||||
|
~Foo();
|
||||||
|
int bar(int x);
|
||||||
|
int x;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Spam {
|
||||||
|
public:
|
||||||
|
Foo *value;
|
||||||
|
...
|
||||||
|
};
|
||||||
|
</pre>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
Now, consider some script code that uses these classes:
|
||||||
|
|
||||||
|
<blockquote>
|
||||||
|
<pre>
|
||||||
|
f = Foo() # Creates a new Foo
|
||||||
|
s = Spam() # Creates a new Spam
|
||||||
|
s.value = f # Stores a reference to f inside s
|
||||||
|
g = s.value # Returns stored reference
|
||||||
|
g = 4 # Reassign g to some other value
|
||||||
|
del f # Destroy f
|
||||||
|
</pre>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
Now, ponder the resulting memory management issues. When objects are
|
||||||
|
created in the script, the objects are wrapped by newly created proxy
|
||||||
|
classes. That is, there is both a new proxy class instance and a new
|
||||||
|
instance of the underlying C++ class. In this example, both
|
||||||
|
<tt>f</tt> and <tt>s</tt> are created in this way. However, the
|
||||||
|
statement <tt>s.value</tt> is rather curious---when executed, a
|
||||||
|
pointer to <tt>f</tt> is stored inside another object. This means
|
||||||
|
that the scripting proxy class <em>AND</em> another C++ class share a
|
||||||
|
reference to the same object. To make matters even more interesting,
|
||||||
|
consider the statement <tt>g = s.value</tt>. When executed, this
|
||||||
|
creates a new proxy class <tt>g</tt> that provides a wrapper around the
|
||||||
|
C++ object stored in <tt>s.value</tt>. In general, there is no way to
|
||||||
|
know where this object came from---it could have been created by the
|
||||||
|
script, but it could also have been generated internally. In this
|
||||||
|
particular example, the assignment of <tt>g</tt> results in a second
|
||||||
|
proxy class for <tt>f</tt>. In other words, a reference to <tt>f</tt>
|
||||||
|
is now shared by two proxy classes <em>and</em> a C++ class.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Finally, consider what happens when objects are destroyed. In the
|
||||||
|
statement, <tt>g=4</tt>, the variable <tt>g</tt> is reassigned. In
|
||||||
|
many languages, this makes the old value of <tt>g</tt> available for
|
||||||
|
garbage collection. Therefore, this causes one of the proxy classes
|
||||||
|
to be destroyed. Later on, the statement <tt>del f</tt> destroys the
|
||||||
|
other proxy class. Of course, there is still a reference to the
|
||||||
|
original object stored inside another C++ object. What happens to it?
|
||||||
|
Is it the object still valid?
|
||||||
|
|
||||||
|
<P>
|
||||||
|
To deal with memory management problems, proxy classes always provide an API
|
||||||
|
for controlling ownership. In C++ pseudocode, ownership control might look
|
||||||
|
roughly like this:
|
||||||
|
|
||||||
|
<blockquote>
|
||||||
|
<pre>
|
||||||
|
class FooProxy {
|
||||||
|
public:
|
||||||
|
Foo *self;
|
||||||
|
int thisown;
|
||||||
|
|
||||||
|
FooProxy() {
|
||||||
|
self = new_Foo();
|
||||||
|
thisown = 1; // Newly created object
|
||||||
|
}
|
||||||
|
~FooProxy() {
|
||||||
|
if (thisown) delete_Foo(self);
|
||||||
|
}
|
||||||
|
...
|
||||||
|
// Ownership control API
|
||||||
|
void disown() {
|
||||||
|
thisown = 0;
|
||||||
|
}
|
||||||
|
void acquire() {
|
||||||
|
thisown = 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class FooPtrProxy: public FooProxy {
|
||||||
|
public:
|
||||||
|
FooPtrProxy(Foo *s) {
|
||||||
|
self = s;
|
||||||
|
thisown = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SpamProxy {
|
||||||
|
...
|
||||||
|
FooProxy *value_get() {
|
||||||
|
return FooPtrProxy(Spam_value_get(self));
|
||||||
|
}
|
||||||
|
void value_set(FooProxy *v) {
|
||||||
|
Spam_value_set(self,v->self);
|
||||||
|
v->disown();
|
||||||
|
}
|
||||||
|
...
|
||||||
|
};
|
||||||
|
</pre>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
Looking at this code, there are a few central features:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Each proxy class keeps an extra flag to indicate ownership. C++ objects are only destroyed
|
||||||
|
if the ownership flag is set.
|
||||||
|
|
||||||
|
<P>
|
||||||
|
<li>When new objects are created in the target language, the ownership flag is set.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<li>When a reference to an internal C++ object is returned, it is wrapped by a proxy
|
||||||
|
class, but the proxy class does not have ownership.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<li>In certain cases, ownership is adjusted. For instance, when a value is assigned to the member of
|
||||||
|
a class, ownership is lost.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<li>Manual ownership control is provided by special <tt>disown()</tt> and <tt>acquire()</tt> methods.
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
Given the tricky nature of C++ memory management, it is impossible for proxy classes to automatically handle
|
||||||
|
every possible memory management problem. However, proxies do provide a mechanism for manual control that
|
||||||
|
can be used (if necessary) to address some of the more tricky memory management problems.
|
||||||
|
|
||||||
|
<h3>Language specific details</h3>
|
||||||
|
|
||||||
|
Language specific details on proxy classes are contained the chapters describing each target language. This
|
||||||
|
chapter has merely introduced the topic in a very general way.
|
||||||
|
|
||||||
<a name="n37"></a><H2>5.26 Where to go for more information</H2>
|
<a name="n37"></a><H2>5.26 Where to go for more information</H2>
|
||||||
|
|
||||||
|
|
@ -3470,6 +3697,6 @@ is the reference document we use to guide a lot of SWIG's C++ support.
|
||||||
|
|
||||||
<p><hr>
|
<p><hr>
|
||||||
|
|
||||||
<address>SWIG 1.3 - Last Modified : May 12, 2002</address>
|
<address>SWIG 1.3 - Last Modified : April 3, 2003</address>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue