Thank  you, Barry! I will modify my code as you suggest.

>> Python may try to delete this instance and that may fail.
fwiw,
I did some testing by having my python code assign the result of this method to a variable and then set the variable to None.
At first it wasn't calling the destructor of my new style class. I printed out reference counts of various objects in python and I noticed that these objects created in C++ code had reference counts one higher than other objects. That is when I added the "owned" argument to self() so that I could get an object with the right reference count. After that, my destructors were being called and I had no problems. I take that to mean Python is deleting the instance successfully. Of course there could be other things wrong that I haven't tested, and it is possible I have been lucky not to run into problems.

Murali


From: Barry Scott <barry@barrys-emacs.org>
To: Murali Donthireddy <donthireddy@yahoo.com>
Cc: PyCXX and improvement <cxx-users@lists.sourceforge.net>
Sent: Sun, October 31, 2010 6:23:32 AM
Subject: Re: PyCXX and new style classes


On 29 Oct 2010, at 00:24, Murali Donthireddy wrote:

Barry,

Thanks for the reply.

BTW, I am using Python2 parts of version 2.6.1 of PyCXX.

I used simple.cxx as my starting point. But all of the methods in "new_style_class" return Py::None. How do I create and return an instance of new_style_class to the python code?  (In my application, I have more than one class, and a method of one class needs to return an instance of another class.)

With some help from someone who knows c++ better than me, I managed to do what I needed and it seems to work. But it felt like a herculean effort.

It would do. You cannot do this from C++ on its own.
You have to create instances of your new style class using python calls.
Python does a lot of house keeping for new style classes that using raw C++
will bypass and lead to who knows what problems.

In pure python you would do this:

class new_style_class:
def __init__( self ):
...

instance = new_style_class()

"new_style_class" is in fact a type. You can call the type to create instances of that type.

In PyCXX the type is available as new_style_class::type().
In simple.cxx you can see that being exposed as the "new_style_class" in the module dictionary.

To create an instance in C++ you need code like this:

        Py::Callable class_type( new_style_class::type() );

        Py::PythonClassObject<new_style_class> new_style_obj( class_type.apply( args, kwds ) );

I have updated the simple.cxx to include a new function (make_instance) that shows this.




I added a second constructor to PythonClass and modified its self() to take an optional "owned" flag. I give all the code further down. 

I think this will lead to problems.


Let us call my subclasses of PythonClass A and B, they each wrap a pre-existing C++ class and hold a shared pointer to instances of those wrapped classes. Let us call the pointers a and b.

I am now able to return  a  PythonClassInstance of B from a method A as follows:
    const WrappedClass* x =  < something that returns an instance of WrappedClass>;
    return (new B(x))->self(true);

Python may try to delete this instance and that may fail.


I must be being monumentally stupid because there is a vast gap between what I had to do and your comment "simple.cxx is all you need". I don't see how that can be the case when simple.cxx doesn't have a single method that returns anything, let alone instances of user defined classes.

Regardless of whether I did more than what was necessary, my extension works beautifully. I think PyCXX is a very nice tool. The fact that I could make changes to it is an indication of how well written it is. I am grateful for your work on PyCXX.


thanks,
Murali

My changes to PythonClass, in header file CXX/Python2/ExtensionType.hxx:

    template<TEMPLATE_TYPENAME T> class PythonClass
    : public PythonExtensionBase
    {
    protected:
[...]
        static PythonClassInstance* alloc_empty() {
            PyObject *py_optlib_expr = extension_object_new(type_object(), Tuple().ptr(), Dict().ptr());
            return reinterpret_cast<PythonClassInstance*>(py_optlib_expr);
        }

        PythonClass()
            : PythonExtensionBase()
            , m_class_instance( alloc_empty() )
        {
            reinterpret_cast< Py::PythonClassInstance * >(selfPtr())->m_pycxx_object = 
                static_cast<PythonExtensionBase*>(this);
        }
public:
        static const T* obj_from_arg(Object arg) {
            PythonClassInstance * b = reinterpret_cast<PythonClassInstance *> (arg.ptr());
            const T *val = static_cast<T *>(b->m_pycxx_object);

Any time you see reinterpret_cast in C++ is often a good sign that the code has a problem.
(Deep library code will need to do this).

Here is a type safe way to do what you want (take from func() in simple.cxx):

                Py::PythonClassObject<new_style_class> x2( x );
                std::cout << "C++ pointer " << x2.getCxxObject() << std::endl;


            return val;
        }
        
        virtual Object self(bool owned = false) // customization: Add optional argument owned.
        {
            return Object( reinterpret_cast<PyObject *>( m_class_instance ), owned );
        }

Because python did not create the class for you you do not have a "self" that is sane.

Given the changes you'll make to get python to create your objects this is not needed.

Barry