[C++-sig] V2: corner case bug?

David Abrahams david.abrahams at rcn.com
Thu Apr 4 02:16:59 CEST 2002


Hi Peter,

Thanks for uncovering this!

Here's what's going on:
* In C++, a const& argument can bind to a temporary rvalue.
* Various from_python converters create the equivalent of temporaries.
For example, a converter which produces a std::vector from a Python
tuple must create a value which won't persist past the call being
executed.
* When the library detects that it can bind a temporary of type T to a
given argument, it must produce storage into which that temporary can be
constructed.
* To do so, it asks what boost::aligmnent_of<T>::value is.

Unfortunately, detecting the alignment of T can only compile when T
doesn't have unimplemented pure virtual functions.

I spent all day thinking that we'd need one or both of the following:

    1. A way to tell the library not to do that for T. I think this
    amounts to a user-specializable is_abstract<T> traits class.

    Upside:
    Users could stop specifying noncopyable as an optional
    class_<> parameter if they specialized is_abstract<T>.

    Downside:
    This is a cumbersome interface technique for users, requiring
closing
    their namespace and opening namespace boost::python. It's prone to
    errors: users may not expose the traits specialization to all
    modules converting T parameters, especially in designs where
    wrapping is an independent, non-intrusive layer from the code being
    wrapped. We could mitigate some of the encumberance by asking a user
    to declare a function like:

        bool operator==(T const&, boost::python::abstract);

    in her own namespace to indicate abstract-ness. However, that idiom
    is not exactly transparent, and doesn't fix the error-prone-ness.


    2. A way to tell the library not to do that for a particular
    argument. In other words, "do NOT bind this argument to an rvalue".
    One way for the user to approximate this is to wrap a forwarding
    function taking a T& argument. Having this capability in the library
    would undoubtedly be useful, but it would be non-trivial to
implement
    and I'm not sure the added complexity is a good idea, either for
    the implementation or for the interface.

Fortunately, there is an alternative which I just thought of:

    3. instead of asking for the alignment of T, I can simply produce
    my best guess at maximally-aligned storage. Downsides: more stack
    memory used per wrapped C++ function (trivial). Can never check that
    the storage is in fact appropriately aligned, whether or not T is
    abstract (because I'll get errors if T /is/ abstract). Upsides:
    simplicity for users. Easy to implement. I can check my alignment
    asumptions when T is exposed as a class, as long as noncopyable
    isn't specified.

I'm planning to implement 3 unless I hear otherwise from people.

-Dave

----- Original Message -----
From: "Peter Bienstman" <pbienst at MIT.EDU>
To: <c++-sig at python.org>
Sent: Tuesday, April 02, 2002 6:02 PM
Subject: [C++-sig] V2: corner case bug?


> OK, this odd combination of abstract base classes, referencing
existing
> objects and adding new functions to a class does not compile.
>
> Wrapping the 'inside' functions goes fine, wrapping the similar
> 'outside' functions doesn't compile because the compiler wants to
> instantiate the abstract class, although it's marked noncopyable.
>
> #define BOOST_PYTHON_DYNAMIC_LIB
> #define BOOST_PYTHON_V2
>
> #include <boost/python/module.hpp>
> #include <boost/python/class.hpp>
> #include <boost/python/reference_existing_object.hpp>
> #include <boost/python/return_value_policy.hpp>
>
> struct A {};
>
> struct V
> {
>
>  virtual void f() = 0;
>
>  const A* inside() {return &a;}
>
>  A a;
> };
>
> const A* outside(const V& v) {return &v.a;}
>
> BOOST_PYTHON_MODULE_INIT(m)
> {
>   using namespace boost::python;
>   using boost::shared_ptr;
>   using boost::python::return_value_policy;
>   using boost::python::reference_existing_object;
>
>   module m("m");
>
>   m
>     .add(class_<A, shared_ptr<A> >("A"))
>
>     .add(
>       class_<V, boost::noncopyable>("V")
>       .def("inside", &V::inside,
>            return_value_policy<reference_existing_object>())
>       .def("outside", outside,
>            return_value_policy<reference_existing_object>())
>       )
>     ;
> }
>
>
>
>
> _______________________________________________
> C++-sig mailing list
> C++-sig at python.org
> http://mail.python.org/mailman/listinfo/c++-sig
>






More information about the Cplusplus-sig mailing list