[C++-sig] alternative smart pointer (intrusive_ptr) example
Jeff Webb
jeff.webb at nta-inc.net
Fri Jul 25 20:29:02 CEST 2008
At the end of my last post, I listed several deficiencies in my proposed python wrapper, mod1.cpp. Let me start by addressing item (2):
> (2) RefHolder objects cannot hold a reference to another RefHolder
> object, even though RefHolder is a subclass of VerbosePointee.
A simple solution to this problem is to add the following statement at the end of BOOST_PYTHON_MODULE(mod1):
implicitly_convertible<intrusive_ptr<RefHolder>,
intrusive_ptr<VerbosePointee> >();
This statement tells boost::python about the relationship between intrusive_ptr<RefHolder> and intrusive_ptr<VerbosePointee> and enables a python user to pass wrapped RefHolder objects to the RefHolder::set_ref function, which is expecting an intrusive_ptr<VerbosePointee>.
Let's see if this actually works:
>>> from mod1 import *
>>> r1 = RefHolder()
creating 0xe49c6e0
>>> r2 = RefHolder()
creating 0xda13bb0
>>> r1.ref = r2
>>> type(r1.ref)
<class 'mod1.RefHolder'>
So far, so good. Now on to the next problem:
> (3) Although a null pointer is translated to python as None, a
> RefHolder's ref member cannot be assigned a value of None.
Let's make sure adding the implicitly_convertible call didn't somehow fix the problem:
>>> r1.ref = None
---------------------------------------------------------------------------
Boost.Python.ArgumentError
Traceback (most recent call last)
ArgumentError: Python argument types in
None.None(RefHolder, NoneType)
did not match C++ signature:
None(RefHolder {lvalue}, boost::intrusive_ptr<VerbosePointee>)
As you can see, this is still an issue. To find a solution, I looked at how the problem was solved for shared_ptr. The solution can be found in this file:
include/boost/python/converter/shared_ptr_from_python.hpp
I basically made a copy of this function, named it 'intrusive_ptr_from_python', replaced shared_ptr with intrusive_ptr, and left the shared_ptr_deleter argument off of the call to the pointer constructor. In order to register this conversion, the function template must be called from BOOST_PYTHON_MODULE(mod1):
boost::python::converter::intrusive_ptr_from_python<VerbosePointee>();
As it turns out, this converter also handles the implicit conversion discussed above, so the implicitly_convertible call is no longer necessary.
Now let's test out our new changes, as shown in the attached file, mod2.cpp.
>>> from mod2 import *
>>> r1 = RefHolder()
creating 0xd78af0
>>> r2 = RefHolder()
creating 0x17ff260
>>> r1.ref = r2
>>> r1.ref is r2
False
>>> r1.ref.id == r2.id
True
>>> type(r1.ref)
<class 'mod2.RefHolder'>
>>> v = VerbosePointee()
creating 0x1817370
>>> r2.ref = v
>>> del r2
>>> r1.ref.ref.id == v.id
True
>>> del v
>>> r1.ref.ref = None
destroying 0x1817370
>>> del r1
destroying 0x17ff260
destroying 0xd78af0
So, it looks like this approach handles two of our issues. The object identity problem still remains, but I will save that discussion for another post. Any questions or comments are welcome.
-Jeff
-------------- next part --------------
A non-text attachment was scrubbed...
Name: mod2.cpp
Type: text/x-c++src
Size: 4506 bytes
Desc: not available
URL: <http://mail.python.org/pipermail/cplusplus-sig/attachments/20080725/1fd4f568/attachment.cpp>
More information about the Cplusplus-sig
mailing list