mirror of
https://github.com/boostorg/python.git
synced 2026-01-23 17:52:17 +00:00
170 lines
13 KiB
HTML
170 lines
13 KiB
HTML
<html>
|
|
<head>
|
|
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
|
<title>Call Policies</title>
|
|
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
|
<link rel="prev" href="functions.html">
|
|
<link rel="next" href="overloading.html">
|
|
</head>
|
|
<body>
|
|
<table width="100%" height="48" border="0" cellspacing="2">
|
|
<tr>
|
|
<td><img src="theme/c%2B%2Bboost.gif">
|
|
</td>
|
|
<td width="85%">
|
|
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Call Policies</b></font>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<br>
|
|
<table border="0">
|
|
<tr>
|
|
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
|
<td width="30"><a href="functions.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
<td width="20"><a href="overloading.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
</tr>
|
|
</table>
|
|
<p>
|
|
In C++, we often deal with arguments and return types such as pointers
|
|
and references. Such primitive types are rather, ummmm, low level and
|
|
they really don't tell us much. At the very least, we don't know the
|
|
owner of the pointer or the referenced object. No wonder languages
|
|
such as Java and Python never deal with such low level entities. In
|
|
C++, it's usually considered a good practice to use smart pointers
|
|
which exactly describe ownership semantics. Still, even good C++
|
|
interfaces use raw references and pointers sometimes, so Boost.Python
|
|
must deal with them. To do this, it may need your help. Consider the
|
|
following C++ function:</p>
|
|
<code><pre>
|
|
<span class=identifier>X</span><span class=special>& </span><span class=identifier>f</span><span class=special>(</span><span class=identifier>Y</span><span class=special>& </span><span class=identifier>y</span><span class=special>, </span><span class=identifier>Z</span><span class=special>* </span><span class=identifier>z</span><span class=special>);
|
|
</span></pre></code>
|
|
<p>
|
|
How should the library wrap this function? A naive approach builds a
|
|
Python X object around result reference. This strategy might or might
|
|
not work out. Here's an example where it didn't</p>
|
|
<code><pre>
|
|
<span class=special>>>> </span><span class=identifier>x </span><span class=special>= </span><span class=identifier>f</span><span class=special>(</span><span class=identifier>y</span><span class=special>, </span><span class=identifier>z</span><span class=special>) </span>##<span class=identifier>x </span><span class=identifier>refers </span><span class=identifier>to </span><span class=identifier>some </span><span class=identifier>C</span><span class=special>++ </span><span class=identifier>X
|
|
</span><span class=special>>>> </span><span class=identifier>del </span><span class=identifier>y
|
|
</span><span class=special>>>> </span><span class=identifier>x</span><span class=special>.</span><span class=identifier>some_method</span><span class=special>() </span>##<span class=identifier>CRASH</span><span class=special>!
|
|
</span></pre></code>
|
|
<p>
|
|
What's the problem?</p>
|
|
<p>
|
|
Well, what if f() was implemented as shown below:</p>
|
|
<code><pre>
|
|
<span class=identifier>X</span><span class=special>& </span><span class=identifier>f</span><span class=special>(</span><span class=identifier>Y</span><span class=special>& </span><span class=identifier>y</span><span class=special>, </span><span class=identifier>Z</span><span class=special>* </span><span class=identifier>z</span><span class=special>)
|
|
{
|
|
</span><span class=identifier>y</span><span class=special>.</span><span class=identifier>z </span><span class=special>= </span><span class=identifier>z</span><span class=special>;
|
|
</span><span class=keyword>return </span><span class=identifier>y</span><span class=special>.</span><span class=identifier>x</span><span class=special>;
|
|
}
|
|
</span></pre></code>
|
|
<p>
|
|
The problem is that the lifetime of result X& is tied to the lifetime
|
|
of y, because the f() returns a reference to a member of the y
|
|
object. This idiom is is not uncommon and perfectly acceptable in the
|
|
context of C++. However, Python users should not be able to crash the
|
|
system just by using our C++ interface. In this case deleting y will
|
|
invalidate the reference to X. We have a dangling reference.</p>
|
|
<p>
|
|
Here's what's happening:</p>
|
|
<ol><li><tt>f</tt> is called passing in a reference to <tt>y</tt> and a pointer to <tt>z</tt></li><li>A reference to <tt>y.x</tt> is returned</li><li><tt>y</tt> is deleted. <tt>x</tt> is a dangling reference</li><li><tt>x.some_method()</tt> is called</li><li><b>BOOM!</b></li></ol><p>
|
|
We could copy result into a new object:</p>
|
|
<code><pre>
|
|
<span class=special>>>> </span><span class=identifier>f</span><span class=special>(</span><span class=identifier>y</span><span class=special>, </span><span class=identifier>z</span><span class=special>).</span><span class=identifier>set</span><span class=special>(</span><span class=number>42</span><span class=special>) </span>##<span class=identifier>Result </span><span class=identifier>disappears
|
|
</span><span class=special>>>> </span><span class=identifier>y</span><span class=special>.</span><span class=identifier>x</span><span class=special>.</span><span class=identifier>get</span><span class=special>() </span>##<span class=identifier>No </span><span class=identifier>crash</span><span class=special>, </span><span class=identifier>but </span><span class=identifier>still </span><span class=identifier>bad
|
|
</span><span class=number>3.14
|
|
</span></pre></code>
|
|
<p>
|
|
This is not really our intent of our C++ interface. We've broken our
|
|
promise that the Python interface should reflect the C++ interface as
|
|
closely as possible.</p>
|
|
<p>
|
|
Our problems do not end there. Suppose Y is implemented as follows:</p>
|
|
<code><pre>
|
|
<span class=keyword>struct </span><span class=identifier>Y
|
|
</span><span class=special>{
|
|
</span><span class=identifier>X </span><span class=identifier>x</span><span class=special>; </span><span class=identifier>Z</span><span class=special>* </span><span class=identifier>z</span><span class=special>;
|
|
</span><span class=keyword>int </span><span class=identifier>z_value</span><span class=special>() { </span><span class=keyword>return </span><span class=identifier>z</span><span class=special>-></span><span class=identifier>value</span><span class=special>(); }
|
|
};
|
|
</span></pre></code>
|
|
<p>
|
|
Notice that the data member <tt>z</tt> is held by class Y using a raw
|
|
pointer. Now we have a potential dangling pointer problem inside Y:</p>
|
|
<code><pre>
|
|
<span class=special>>>> </span><span class=identifier>x </span><span class=special>= </span><span class=identifier>f</span><span class=special>(</span><span class=identifier>y</span><span class=special>, </span><span class=identifier>z</span><span class=special>) </span>##<span class=identifier>y </span><span class=identifier>refers </span><span class=identifier>to </span><span class=identifier>z
|
|
</span><span class=special>>>> </span><span class=identifier>del </span><span class=identifier>z </span>##<span class=identifier>Kill </span><span class=identifier>the </span><span class=identifier>z </span><span class=identifier>object
|
|
</span><span class=special>>>> </span><span class=identifier>y</span><span class=special>.</span><span class=identifier>z_value</span><span class=special>() </span>##<span class=identifier>CRASH</span><span class=special>!
|
|
</span></pre></code>
|
|
<p>
|
|
For reference, here's the implementation of <tt>f</tt> again:</p>
|
|
<code><pre>
|
|
<span class=identifier>X</span><span class=special>& </span><span class=identifier>f</span><span class=special>(</span><span class=identifier>Y</span><span class=special>& </span><span class=identifier>y</span><span class=special>, </span><span class=identifier>Z</span><span class=special>* </span><span class=identifier>z</span><span class=special>)
|
|
{
|
|
</span><span class=identifier>y</span><span class=special>.</span><span class=identifier>z </span><span class=special>= </span><span class=identifier>z</span><span class=special>;
|
|
</span><span class=keyword>return </span><span class=identifier>y</span><span class=special>.</span><span class=identifier>x</span><span class=special>;
|
|
}
|
|
</span></pre></code>
|
|
<p>
|
|
Here's what's happening:</p>
|
|
<ol><li><tt>f</tt> is called passing in a reference to <tt>y</tt> and a pointer to <tt>z</tt></li><li>A pointer to <tt>z</tt> is held by <tt>y</tt></li><li>A reference to <tt>y.x</tt> is returned</li><li><tt>z</tt> is deleted. <tt>y.z</tt> is a dangling pointer</li><li><tt>y.z_value()</tt> is called</li><li><tt>z->value()</tt> is called</li><li><b>BOOM!</b></li></ol><a name="call_policies"></a><h2>Call Policies</h2><p>
|
|
Call Policies may be used in situations such as the example detailed above.
|
|
In our example, <tt>return_internal_reference</tt> and <tt>with_custodian_and_ward</tt>
|
|
are our friends:</p>
|
|
<code><pre>
|
|
<span class=identifier>def</span><span class=special>(</span><span class=string>"f"</span><span class=special>, </span><span class=identifier>f</span><span class=special>,
|
|
</span><span class=identifier>return_internal_reference</span><span class=special><</span><span class=number>1</span><span class=special>,
|
|
</span><span class=identifier>with_custodian_and_ward</span><span class=special><</span><span class=number>1</span><span class=special>, </span><span class=number>2</span><span class=special>> >());
|
|
</span></pre></code>
|
|
<p>
|
|
What are the <tt>1</tt> and <tt>2</tt> parameters, you ask?</p>
|
|
<code><pre>
|
|
<span class=identifier>return_internal_reference</span><span class=special><</span><span class=number>1
|
|
</span></pre></code>
|
|
<p>
|
|
Informs Boost.Python that the first argument, in our case <tt>Y& y</tt>, is the
|
|
owner of the returned reference: <tt>X&</tt>. The "<tt>1</tt>" simply specifies the
|
|
first argument. In short: "return an internal reference <tt>X&</tt> owned by the
|
|
1st argument <tt>Y& y</tt>".</p>
|
|
<code><pre>
|
|
<span class=identifier>with_custodian_and_ward</span><span class=special><</span><span class=number>1</span><span class=special>, </span><span class=number>2</span><span class=special>>
|
|
</span></pre></code>
|
|
<p>
|
|
Informs Boost.Python that the lifetime of the argument indicated by ward
|
|
(i.e. the 2nd argument: <tt>Z* z</tt>) is dependent on the lifetime of the
|
|
argument indicated by custodian (i.e. the 1st argument: <tt>Y& y</tt>).</p>
|
|
<p>
|
|
It is also important to note that we have defined two policies above. Two
|
|
or more policies can be composed by chaining. Here's the general syntax:</p>
|
|
<code><pre>
|
|
<span class=identifier>policy1</span><span class=special><</span><span class=identifier>args</span><span class=special>...,
|
|
</span><span class=identifier>policy2</span><span class=special><</span><span class=identifier>args</span><span class=special>...,
|
|
</span><span class=identifier>policy3</span><span class=special><</span><span class=identifier>args</span><span class=special>...> > >
|
|
</span></pre></code>
|
|
<p>
|
|
Here is the list of predefined call policies. A complete reference detailing
|
|
these can be found <a href="../../v2/reference.html#models_of_call_policies">
|
|
here</a>.</p>
|
|
<ul><li><b>with_custodian_and_ward</b><br> Ties lifetimes of the arguments</li><li><b>with_custodian_and_ward_postcall</b><br> Ties lifetimes of the arguments and results</li><li><b>return_internal_reference</b><br> Ties lifetime of one argument to that of result</li><li><b>return_value_policy<T> with T one of:</b><br></li><li><b>reference_existing_object</b><br>naïve (dangerous) approach</li><li><b>copy_const_reference</b><br>Boost.Python v1 approach</li><li><b>copy_non_const_reference</b><br></li><li><b>manage_new_object</b><br> Adopt a pointer and hold the instance</li></ul><table width="80%" border="0" align="center">
|
|
<tr>
|
|
<td class="note_box">
|
|
<img src="theme/smiley.gif"></img> <b>Remember the Zen, Luke:</b><br><br>
|
|
"Explicit is better than implicit"<br>
|
|
"In the face of ambiguity, refuse the temptation to guess"<br> </td>
|
|
</tr>
|
|
</table>
|
|
<table border="0">
|
|
<tr>
|
|
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
|
<td width="30"><a href="functions.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
<td width="20"><a href="overloading.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
</tr>
|
|
</table>
|
|
<br>
|
|
<hr size="1"><p class="copyright">Copyright © 2002-2003 David Abrahams<br>Copyright © 2002-2003 Joel de Guzman<br><br>
|
|
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
|
is granted provided this copyright notice appears in all copies. This document
|
|
is provided "as is" without express or implied warranty, and with
|
|
no claim as to its suitability for any purpose. </font> </p>
|
|
</body>
|
|
</html>
|