Boost logo

Boost Users :

From: Nat Goodspeed (ngoodspeed_at_[hidden])
Date: 2005-09-02 19:31:58


We have a smart_ptr template of our own, sort of cloned from
intrusive_ptr. But I'm having trouble with Python code passing subclass
objects managed by this smart_ptr to C++ methods accepting
smart_ptr<base class>.

Consider:

class Base: { ... };

class SubClass: public Base { ... };

class Interface
{
public:
    void method(smart_ptr<Base> arg) const;
};

Of course SubClass* is implicitly convertible to Base*. In C++ code,
smart_ptr<SubClass> is even implicitly convertible to smart_ptr<Base>.
That is, given the definitions above, this C++ code compiles and runs
correctly:

    Interface worker;
    smart_ptr<SubClass> objp = new SubClass();
    worker.method(objp);

We can inform Boost.Python that Base objects -- and, by implication,
SubClass as well -- are to be managed using smart_ptr<>.

    class_<Base, smart_ptr<Base>, boost::noncopyable>("Base", no_init)
        ...
    ;

    class_<SubClass, bases<Base> >("SubClass")
        ...
    ;

We have many methods that accept smart_ptr<Base> and do appropriately
polymorphic things to SubClass and its siblings. However, if a Python
caller attempts to pass a SubClass object to a method accepting
smart_ptr<Base>:

obj = Extension.SubClass()
worker = Extension.Interface()
worker.method(obj)

we get the following runtime error:

Boost.Python.ArgumentError: Python argument types in
    Interface.method(Interface, SubClass)
did not match C++ signature:
    method(class Interface {lvalue}, class smart_ptr<class Base>)

That's true for both Boost 1.31 and Boost 1.32. We have not yet tried
this with Boost 1.33. We're using MSVC 7.1 on Windows XP Pro.

Okay, I know this is our fault, something's wrong with our smart_ptr
template definition. I know that because if I recompile with this:

#define smart_ptr boost::shared_ptr

instead of our own smart_ptr definition, it works just fine!

As noted earlier, our smart_ptr is a variant of boost::intrusive_ptr.
But it appears that either there's a mysterious requirement on the
smart_ptr template that we're not fulfilling, or there's special
recognition of boost::shared_ptr and possibly boost::intrusive_ptr in
Boost.Python.

What must we add to allow Boost.Python to recognize the legal conversion
from smart_ptr<SubClass> to smart_ptr<Base> when it does its argument
matching?

[Your next question is: why not just use one of the Boost smart
pointers? Short answer: that's what we WANTED to do! We tried shared_ptr
and ran afoul of the second-conversion-from-same-dumb-pointer problem;
we tried intrusive_ptr and got completely entangled in new cross-DLL
dependencies because intrusive_ptr doesn't deal well with incomplete
pointee types. Our smart_ptr is an attempt to trade away both issues, at
the cost of a mandatory pointee base class. It almost works, too, except
for this baffling bug...]

Thanks for your help.







Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net