I'm trying to clone a Python object from C++. The Python class inherits from an exposed C++ base class. To avoid the dangling pointer problem, I keep a Python reference to the created Python object like this... from hippo import FunctionBase # Define a class in Python that is derived from C++ base class _clones = [] class Linear ( FunctionBase ) : def __init__ ( self ) : FunctionBase.__init__( self ) self.initialize () def clone ( self ) : _clones.append ( Linear () ) return _clones[-1] Then in the C++ wrapper class, I have FunctionBase * FunctionWrap:: clone () const // overrides FunctionBase::clone() { #ifndef HAVE_OLD_PYTHON PyGILState_STATE state = PyGILState_Ensure (); object py_result; if (override clone = this->get_override("clone")) { try { // The Python class author overrode clone; do // whatever she says py_result = clone(); } catch ( error_already_set & e ) { PyErr_Print (); handle_exception (); PyGILState_Release ( state ); return 0; } } else { The Python implemented clone() member function is called but I get the following error message on return ... TypeError: No registered converter was able to extract a C++ reference to type boost::python::api::object from this Python object of type Linear Any suggestions?
"Paul F. Kunz" <Paul_Kunz@slac.stanford.edu> writes:
FunctionBase * FunctionWrap:: clone () const // overrides FunctionBase::clone() { #ifndef HAVE_OLD_PYTHON PyGILState_STATE state = PyGILState_Ensure (); object py_result; if (override clone = this->get_override("clone")) { try { // The Python class author overrode clone; do // whatever she says py_result = clone();
The result of invoking an override is not meant to be used this way, but you might be able to force it by doing: py_result = boost::implicit_cast<object>(clone()); What compiler are you using, incidentally? -- Dave Abrahams Boost Consulting www.boost-consulting.com
On Tue, 02 Aug 2005 23:39:50 -0400, David Abrahams <dave@boost-consulting.com> said:
The result of invoking an override is not meant to be used this way, but you might be able to force it by doing:
py_result = boost::implicit_cast<object>(clone());
Tried that and didn't get an error at runtime. However, the very next call to the object unsigned int FunctionWrap:: dimensions () const { unsigned int dims = 0; if ( override member = this -> get_override ( "dimensions" ) ) { dims = member(); } else { // didn't override it dims = FunctionBase::dimensions (); } return dims; } leads to Program received signal SIGSEGV, Segmentation fault. [Switching to Thread -1222050896 (LWP 14423)] PyErr_Restore (type=0xb75a671c, value=0xb74827b8, traceback=0x0) at Python/errors.c:33 (gdb) up #1 0x080ceb80 in PyErr_Format (exception=0xb75a671c, format=0xb75a671c "\006") at Python/errors.c:51 (gdb) #2 0x0807f3a0 in PyObject_GenericGetAttr (obj=0xb756c464, name=0xb7532cc8) at Objects/object.c:1303 (gdb) #3 0x0807ec79 in PyObject_GetAttrString (v=0xb756c464, name=0x7d1ae5 "dimensions") at Objects/object.c:1016 (gdb) #4 0x009ebcf9 in boost::python::detail::wrapper_base::get_override () from /usr/local/lib/libboost_python-gcc-1_32.so.1.32.0 (gdb) #5 0x00736447 in FunctionWrap::dimensions (this=0x94c7f40) at /usr/local/include/boost-1_32/boost/python/wrapper.hpp:29 Current language: auto; currently c++ (gdb) The object does *not* have "dimension" member function. If I give it one, I get the same error. By the way, the rest of the code in the clone() method of FunctionWrap executed without errors, namely FunctionWrap* result = extract<FunctionWrap*>(py_result); // Make the C++ result control the destiny of the Python result. result->invert_ownership = py_result; PyGILState_Release ( state ); return result; }
What compiler are you using, incidentally?
gcc 4.0.1 and gcc 3.2.3
"Paul F. Kunz" <Paul_Kunz@slac.stanford.edu> writes:
On Tue, 02 Aug 2005 23:39:50 -0400, David Abrahams <dave@boost-consulting.com> said:
The result of invoking an override is not meant to be used this way, but you might be able to force it by doing:
py_result = boost::implicit_cast<object>(clone());
Tried that and didn't get an error at runtime. However, the very next call to the object
unsigned int FunctionWrap:: dimensions () const { unsigned int dims = 0;
if ( override member = this -> get_override ( "dimensions" ) ) { dims = member(); } else { // didn't override it dims = FunctionBase::dimensions (); } return dims; }
leads to
Program received signal SIGSEGV, Segmentation fault. [Switching to Thread -1222050896 (LWP 14423)] PyErr_Restore (type=0xb75a671c, value=0xb74827b8, traceback=0x0) at Python/errors.c:33 (gdb) up #1 0x080ceb80 in PyErr_Format (exception=0xb75a671c, format=0xb75a671c "\006") at Python/errors.c:51 (gdb) #2 0x0807f3a0 in PyObject_GenericGetAttr (obj=0xb756c464, name=0xb7532cc8) at Objects/object.c:1303 (gdb) #3 0x0807ec79 in PyObject_GetAttrString (v=0xb756c464, name=0x7d1ae5 "dimensions") at Objects/object.c:1016 (gdb) #4 0x009ebcf9 in boost::python::detail::wrapper_base::get_override () from /usr/local/lib/libboost_python-gcc-1_32.so.1.32.0 (gdb) #5 0x00736447 in FunctionWrap::dimensions (this=0x94c7f40) at /usr/local/include/boost-1_32/boost/python/wrapper.hpp:29 Current language: auto; currently c++ (gdb)
I'm pretty sure that's an unrelated problem, and something you did is corrupting memory somewhere.
The object does *not* have "dimension" member function.
That's not relevant.
If I give it one, I get the same error. By the way, the rest of the code in the clone() method of FunctionWrap executed without errors, namely
FunctionWrap* result = extract<FunctionWrap*>(py_result);
// Make the C++ result control the destiny of the Python result. result->invert_ownership = py_result; PyGILState_Release ( state );
I"m not sure about this invert_ownership business. Are you sure you're not allowing your Python object to be destroyed prematurely? -- Dave Abrahams Boost Consulting www.boost-consulting.com
On Wed, 03 Aug 2005 11:01:41 -0400, David Abrahams <dave@boost-consulting.com> said:
I'm pretty sure that's an unrelated problem, and something you did is corrupting memory somewhere.
Thanks for the tip. I found that a function object created not by clone method also has the same problem. This used to work, so indeed I have some other problem.
I"m not sure about this invert_ownership business. Are you sure you're not allowing your Python object to be destroyed prematurely?
Pretty sure. The C++ code just create a new instance and is about to use it. Thanks again.
--- "Paul F. Kunz" <Paul_Kunz@slac.stanford.edu> wrote:
On Wed, 03 Aug 2005 11:01:41 -0400, David Abrahams <dave@boost-consulting.com> said:
I'm pretty sure that's an unrelated problem, and something you did is corrupting memory somewhere.
Thanks for the tip. I found that a function object created not by clone method also has the same problem. This used to work, so indeed I have some other problem.
Anytime I see a Segfault or Abort my standard response is to run valgrind. It is an extremely simple and powerful way of pinpointing the problem. http://www.valgrind.org/ Cheers, Ralf __________________________________________________ Do You Yahoo!? Tired of spam? Yahoo! Mail has the best spam protection around http://mail.yahoo.com
On Wed, 3 Aug 2005 10:10:21 -0700 (PDT), "Ralf W. Grosse-Kunstleve" <rwgk@yahoo.com> said:
--- "Paul F. Kunz" <Paul_Kunz@slac.stanford.edu> wrote:
> On Wed, 03 Aug 2005 11:01:41 -0400, David Abrahams <dave@boost-consulting.com> said:
I'm pretty sure that's an unrelated problem, and something you did > is corrupting memory somewhere.
Dave, you were right. I was doing something very stupid somewhere else. The object was not being destroyed.
Anytime I see a Segfault or Abort my standard response is to run valgrind. It is an extremely simple and powerful way of pinpointing the problem.
Thanks for the tip, Ralf.
I'm having trouble with clone, again, but this time only with VC-8.0. I get the following error message ... ;; This buffer is for notes you don't want to save, and for Lisp evaluation. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer. Compiling... FunctionWrap.cxx ..\..\python\FunctionWrap.cxx(188) : error C2664: 'boost::implicit_cast' : cannot convert parameter 1 from 'boost::python::detail::method_result' to 'boost::python::api::object' No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called The code is clone () const { #ifndef HAVE_OLD_PYTHON PyGILState_STATE state = PyGILState_Ensure (); object py_result; if (override clone = this->get_override("clone")) { try { // The Python class author overrode clone; do // whatever she says py_result = boost::implicit_cast < object > ( clone() ); } catch ( error_already_set & ) { The same code works for gcc 3.2, and 4.0. on Linux and VC 7.1 on Windows with Boost_1_32. Neither Boost version 1_32_0 nore 1_33_1 works for VC 8.0. Any ideas?
"Paul F. Kunz" <Paul_Kunz@slac.stanford.edu> writes:
I'm having trouble with clone, again, but this time only with VC-8.0. I get the following error message ...
;; This buffer is for notes you don't want to save, and for Lisp evaluation. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer.
Compiling... FunctionWrap.cxx ..\..\python\FunctionWrap.cxx(188) : error C2664: 'boost::implicit_cast' : cannot convert parameter 1 from 'boost::python::detail::method_result' to 'boost::python::api::object' No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
The code is
clone () const { #ifndef HAVE_OLD_PYTHON PyGILState_STATE state = PyGILState_Ensure ();
object py_result;
if (override clone = this->get_override("clone")) { try { // The Python class author overrode clone; do // whatever she says py_result = boost::implicit_cast < object > ( clone() ); } catch ( error_already_set & ) {
The same code works for gcc 3.2, and 4.0. on Linux and VC 7.1 on Windows with Boost_1_32. Neither Boost version 1_32_0 nore 1_33_1 works for VC 8.0.
Any ideas?
Well, I'm surprised it works anywhere. method_result has an implicit conversion _to_ any type, and object has an implicit conversion _from_ any type. If that's not ambiguous on a fully-conforming compiler, it might be close enough to confuse vc8. -- Dave Abrahams Boost Consulting www.boost-consulting.com
On Thu, 23 Feb 2006 09:02:56 -0500, David Abrahams <dave@boost-consulting.com> said:
Well, I'm surprised it works anywhere. method_result has an implicit conversion _to_ any type, and object has an implicit conversion _from_ any type. If that's not ambiguous on a fully-conforming compiler, it might be close enough to confuse vc8.
You suggested this code to me last year. Any ideas on rewriting it so it compiles with VC++ 8?
"Paul F. Kunz" <Paul_Kunz@slac.stanford.edu> writes:
On Thu, 23 Feb 2006 09:02:56 -0500, David Abrahams <dave@boost-consulting.com> said:
Well, I'm surprised it works anywhere. method_result has an implicit conversion _to_ any type, and object has an implicit conversion _from_ any type. If that's not ambiguous on a fully-conforming compiler, it might be close enough to confuse vc8.
You suggested this code to me last year. Any ideas on rewriting it so it compiles with VC++ 8?
Instead of implicit_cast, maybe try: object py_result( clone() ); -- Dave Abrahams Boost Consulting www.boost-consulting.com
On Fri, 24 Feb 2006 11:19:04 -0500, David Abrahams <dave@boost-consulting.com> said:
"Paul F. Kunz" <Paul_Kunz@slac.stanford.edu> writes:
> On Thu, 23 Feb 2006 09:02:56 -0500, David Abrahams > <dave@boost-consulting.com> said:
Well, I'm surprised it works anywhere. method_result has an implicit conversion _to_ any type, and object has an implicit conversion _from_ any type. If that's not ambiguous on a fully-conforming compiler, it might be close enough to confuse vc8. You suggested this code to me last year. Any ideas on rewriting it so it compiles with VC++ 8?
Instead of implicit_cast, maybe try:
object py_result( clone() );
Many thanks Dave, that works.
"Paul F. Kunz" <Paul_Kunz@slac.stanford.edu> writes:
On Fri, 24 Feb 2006 11:19:04 -0500, David Abrahams <dave@boost-consulting.com> said:
"Paul F. Kunz" <Paul_Kunz@slac.stanford.edu> writes:
>> On Thu, 23 Feb 2006 09:02:56 -0500, David Abrahams >> <dave@boost-consulting.com> said:
Well, I'm surprised it works anywhere. method_result has an implicit conversion _to_ any type, and object has an implicit conversion _from_ any type. If that's not ambiguous on a fully-conforming compiler, it might be close enough to confuse vc8. You suggested this code to me last year. Any ideas on rewriting it so it compiles with VC++ 8?
Instead of implicit_cast, maybe try:
object py_result( clone() );
Many thanks Dave, that works.
You're welcome. Did you submit a bug report to Microsoft? If not, please do! That's how you can pay me back :) -- Dave Abrahams Boost Consulting www.boost-consulting.com
participants (3)
-
David Abrahams -
Paul F. Kunz -
Ralf W. Grosse-Kunstleve