1<html> 2<head> 3<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 4<title>How can I find the existing PyObject that holds a C++ object?</title> 5<link rel="stylesheet" href="../boostbook.css" type="text/css"> 6<meta name="generator" content="DocBook XSL Stylesheets V1.79.1"> 7<link rel="home" href="../index.html" title="Boost.Python"> 8<link rel="up" href="../faq.html" title="Chapter 5. Frequently Asked Questions (FAQs)"> 9<link rel="prev" href="does_boost_python_work_with_mac_.html" title="Does Boost.Python work with Mac OS X?"> 10<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?"> 11</head> 12<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"> 13<table cellpadding="2" width="100%"><tr><td valign="top"><img alt="" width="" height="" src="../images/boost.png"></td></tr></table> 14<hr> 15<div class="spirit-nav"> 16<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> 17</div> 18<div class="section"> 19<div class="titlepage"><div><div><h3 class="title"> 20<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 21 the existing PyObject that holds a C++ object?</a> 22</h3></div></div></div> 23<div class="blockquote"><blockquote class="blockquote"><p> 24 "I am wrapping a function that always returns a pointer to an already-held 25 C++ object." 26 </p></blockquote></div> 27<p> 28 One way to do that is to hijack the mechanisms used for wrapping a class 29 with virtual functions. If you make a wrapper class with an initial PyObject* 30 constructor argument and store that PyObject* as "self", you can 31 get back to it by casting down to that wrapper type in a thin wrapper function. 32 For example: 33 </p> 34<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> 35<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> 36 37 38<span class="comment">// wrapping code</span> 39 40<span class="keyword">struct</span> <span class="identifier">X_wrap</span> <span class="special">:</span> <span class="identifier">X</span> 41<span class="special">{</span> 42 <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> 43 <span class="identifier">PyObject</span><span class="special">*</span> <span class="identifier">self</span><span class="special">;</span> 44<span class="special">};</span> 45 46<span class="identifier">handle</span><span class="special"><></span> <span class="identifier">f_wrap</span><span class="special">()</span> 47<span class="special">{</span> 48 <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"><</span><span class="identifier">X_wrap</span><span class="special">*>(</span><span class="identifier">f</span><span class="special">());</span> 49 <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> 50 <span class="keyword">return</span> <span class="identifier">handle</span><span class="special"><>(</span><span class="identifier">borrowed</span><span class="special">(</span><span class="identifier">xw</span><span class="special">-></span><span class="identifier">self</span><span class="special">));</span> 51<span class="special">}</span> 52 53<span class="special">...</span> 54 55<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> 56<span class="identifier">class_</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">boost</span><span class="special">::</span><span class="identifier">noncopyable</span><span class="special">>(</span><span class="string">"X"</span><span class="special">,</span> <span class="identifier">init</span><span class="special"><</span><span class="keyword">int</span><span class="special">>())</span> 57 <span class="special">...</span> 58 <span class="special">;</span> 59</pre> 60<p> 61 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> 62 with no runtime check that it's valid. This approach also only works if the 63 <code class="computeroutput"><span class="identifier">X</span></code> object was constructed 64 from Python, because <code class="computeroutput"><span class="identifier">X</span></code>s constructed 65 from C++ are of course never <code class="computeroutput"><span class="identifier">X_wrap</span></code> 66 objects. 67 </p> 68<p> 69 Another approach to this requires you to change your C++ code a bit; if that's 70 an option for you it might be a better way to go. work we've been meaning 71 to get to anyway. When a <code class="computeroutput"><span class="identifier">shared_ptr</span><span class="special"><</span><span class="identifier">X</span><span class="special">></span></code> 72 is converted from Python, the shared_ptr actually manages a reference to 73 the containing Python object. When a shared_ptr<X> is converted back 74 to Python, the library checks to see if it's one of those "Python object 75 managers" and if so just returns the original Python object. So you 76 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 77 the Python object back. To exploit this you'd have to be able to change the 78 C++ code you're wrapping so that it deals with shared_ptr instead of raw 79 pointers. 80 </p> 81<p> 82 There are other approaches too. The functions that receive the Python object 83 that you eventually want to return could be wrapped with a thin wrapper that 84 records the correspondence between the object address and its containing 85 Python object, and you could have your f_wrap function look in that mapping 86 to get the Python object out. 87 </p> 88</div> 89<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr> 90<td align="left"></td> 91<td align="right"><div class="copyright-footer">Copyright © 2002-2015 David 92 Abrahams, Stefan Seefeld<p> 93 Distributed under the Boost Software License, Version 1.0. (See accompanying 94 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>) 95 </p> 96</div></td> 97</tr></table> 98<hr> 99<div class="spirit-nav"> 100<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> 101</div> 102</body> 103</html> 104