summaryrefslogtreecommitdiff
path: root/libs/python/doc/html/faq/how_can_i_find_the_existing_pyob.html
blob: f0ba51f938e3f98b764d1b062ab314501167c947 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>How can I find the existing PyObject that holds a C++ object?</title>
<link rel="stylesheet" href="../boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="../index.html" title="Boost.Python">
<link rel="up" href="../faq.html" title="Chapter&#160;4.&#160;Frequently Asked Questions (FAQs)">
<link rel="prev" href="does_boost_python_work_with_mac_.html" title="Does Boost.Python work with Mac OS X?">
<link rel="next" href="how_can_i_wrap_a_function_which0.html" title="How can I wrap a function which needs to take ownership of a raw pointer?">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr><td valign="top"><img alt="" width="" height="" src="../images/boost.png"></td></tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="does_boost_python_work_with_mac_.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../faq.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="how_can_i_wrap_a_function_which0.html"><img src="../images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="faq.how_can_i_find_the_existing_pyob"></a><a class="link" href="how_can_i_find_the_existing_pyob.html" title="How can I find the existing PyObject that holds a C++ object?">How can I find
      the existing PyObject that holds a C++ object?</a>
</h3></div></div></div>
<div class="blockquote"><blockquote class="blockquote"><p>
          "I am wrapping a function that always returns a pointer to an already-held
          C++ object."
        </p></blockquote></div>
<p>
        One way to do that is to hijack the mechanisms used for wrapping a class
        with virtual functions. If you make a wrapper class with an initial PyObject*
        constructor argument and store that PyObject* as "self", you can
        get back to it by casting down to that wrapper type in a thin wrapper function.
        For example:
      </p>
<pre class="programlisting"><span class="keyword">class</span> <span class="identifier">X</span> <span class="special">{</span> <span class="identifier">X</span><span class="special">(</span><span class="keyword">int</span><span class="special">);</span> <span class="keyword">virtual</span> <span class="special">~</span><span class="identifier">X</span><span class="special">();</span> <span class="special">...</span> <span class="special">};</span>
<span class="identifier">X</span><span class="special">*</span> <span class="identifier">f</span><span class="special">();</span>  <span class="comment">// known to return Xs that are managed by Python objects</span>


<span class="comment">// wrapping code</span>

<span class="keyword">struct</span> <span class="identifier">X_wrap</span> <span class="special">:</span> <span class="identifier">X</span>
<span class="special">{</span>
  <span class="identifier">X_wrap</span><span class="special">(</span><span class="identifier">PyObject</span><span class="special">*</span> <span class="identifier">self</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">v</span><span class="special">)</span> <span class="special">:</span> <span class="identifier">self</span><span class="special">(</span><span class="identifier">self</span><span class="special">),</span> <span class="identifier">X</span><span class="special">(</span><span class="identifier">v</span><span class="special">)</span> <span class="special">{}</span>
  <span class="identifier">PyObject</span><span class="special">*</span> <span class="identifier">self</span><span class="special">;</span>
<span class="special">};</span>

<span class="identifier">handle</span><span class="special">&lt;&gt;</span> <span class="identifier">f_wrap</span><span class="special">()</span>
<span class="special">{</span>
  <span class="identifier">X_wrap</span><span class="special">*</span> <span class="identifier">xw</span> <span class="special">=</span> <span class="keyword">dynamic_cast</span><span class="special">&lt;</span><span class="identifier">X_wrap</span><span class="special">*&gt;(</span><span class="identifier">f</span><span class="special">());</span>
  <span class="identifier">assert</span><span class="special">(</span><span class="identifier">xw</span> <span class="special">!=</span> <span class="number">0</span><span class="special">);</span>
  <span class="keyword">return</span> <span class="identifier">handle</span><span class="special">&lt;&gt;(</span><span class="identifier">borrowed</span><span class="special">(</span><span class="identifier">xw</span><span class="special">-&gt;</span><span class="identifier">self</span><span class="special">));</span>
<span class="special">}</span>

<span class="special">...</span>

<span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">f_wrap</span><span class="special">());</span>
<span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">X</span><span class="special">,</span><span class="identifier">X_wrap</span><span class="special">,</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">noncopyable</span><span class="special">&gt;(</span><span class="string">"X"</span><span class="special">,</span> <span class="identifier">init</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;())</span>
 <span class="special">...</span>
 <span class="special">;</span>
</pre>
<p>
        Of course, if X has no virtual functions you'll have to use <code class="computeroutput"><span class="keyword">static_cast</span></code> instead of <code class="computeroutput"><span class="keyword">dynamic_cast</span></code>
        with no runtime check that it's valid. This approach also only works if the
        <code class="computeroutput"><span class="identifier">X</span></code> object was constructed
        from Python, because <code class="computeroutput"><span class="identifier">X</span></code>s constructed
        from C++ are of course never <code class="computeroutput"><span class="identifier">X_wrap</span></code>
        objects.
      </p>
<p>
        Another approach to this requires you to change your C++ code a bit; if that's
        an option for you it might be a better way to go. work we've been meaning
        to get to anyway. When a <code class="computeroutput"><span class="identifier">shared_ptr</span><span class="special">&lt;</span><span class="identifier">X</span><span class="special">&gt;</span></code>
        is converted from Python, the shared_ptr actually manages a reference to
        the containing Python object. When a shared_ptr&lt;X&gt; is converted back
        to Python, the library checks to see if it's one of those "Python object
        managers" and if so just returns the original Python object. So you
        could just write <code class="computeroutput"><span class="identifier">object</span><span class="special">(</span><span class="identifier">p</span><span class="special">)</span></code> to get
        the Python object back. To exploit this you'd have to be able to change the
        C++ code you're wrapping so that it deals with shared_ptr instead of raw
        pointers.
      </p>
<p>
        There are other approaches too. The functions that receive the Python object
        that you eventually want to return could be wrapped with a thin wrapper that
        records the correspondence between the object address and its containing
        Python object, and you could have your f_wrap function look in that mapping
        to get the Python object out.
      </p>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2002-2015 David
      Abrahams, Stefan Seefeld<p>
        Distributed under the Boost Software License, Version 1.0. (See accompanying
        file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
      </p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="does_boost_python_work_with_mac_.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../faq.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="how_can_i_wrap_a_function_which0.html"><img src="../images/next.png" alt="Next"></a>
</div>
</body>
</html>