[C++-sig] rfe: change of behaviour with return_internal_reference policy

David Abrahams dave at boost-consulting.com
Mon Aug 19 15:25:28 CEST 2002


-----------------------------------------------------------
           David Abrahams * Boost Consulting
dave at boost-consulting.com * http://www.boost-consulting.com


----- Original Message -----
From: "gideon may" <gideon at computer.org>
To: "pysig" <c++-sig at python.org>
Sent: Monday, August 19, 2002 9:10 AM
Subject: [C++-sig] rfe: change of behaviour with return_internal_reference
policy


> Dear Dave,
>
> I have the following code example (obvious stuff missing :
> <============================================
> class Node {
> };
>
> class Leaf1 : public Node {
> };
>
> class Leaf2 : public Node {
> };
>
> class Group : public Node {
>   public:
>     void addChild(Node * child) { _child = child; }
>     Node * getChild() { return _child; }
>   private:
>     Node * _child;
> };
>
> toGroup(Node * self) {    return dynamic_cast<Group *>(self); }
>
> toLeaf1(Node * self) {    return dynamic_cast<Leaf1 *>(self); }
>
> toLeaf2(Node * self) {    return dynamic_cast<Leaf2 *>(self); }
>
> BOOST_PYTHON_MODULE_INIT(cast)
> {
>     module("cast")
>         .add(class_<Node>("Node")
>             .def_init()
>             .def("toGroup", &nodeToGroup, return_internal_reference<>())
>             .def("toLeaf1", &nodeToLeaf1, return_internal_reference<>())
>             .def("toLeaf2", &nodeToLeaf2, return_internal_reference<>())
>          )
>          .add(class_<Group>("Group")
>          .add(class_<Leaf1>("Leaf1")
>          .add(class_<Leaf2>("Leaf2")
>     ;
> }
> =======================================>
>
> this allows me to do stuff like :
>
> >>> g = Group()
> >>> n = g.getChild()
> >>> l1 = n.toLeaf1()
> >>> if l1:
> >>>     print "I'm leaf1"
> >>> l2 = n.toLeaf2()
> >>> if l2:
> >>>     print "I'm leaf2"
>
> Unfortunately it doesn't work, because of the weak references being used
> with return_internal_reference.
> It seems that within make_nurse_and_patient (life_support.cpp), a weak
> reference is being
> created between the result and the originator.

No, not exactly. We're creating a weak reference from the result to a
life_support object, which holds a reference to the originator and to the
weak reference. It's a sick little trick which keeps the originator alive
as long as the result is.

> In my case the result can be
> a NULL pointer,

Which gets translated to None.

> failing
> the PyWeakref_NewRef function.

Ah yes; None doesn't support weak references.

> If however a check is made that the nurse is
> an object supporting
> weak references the function continues as intended else returning a
PyNone,
> then
> my code works. Thus inserting
>
> if (!PyType_SUPPORTS_WEAKREFS(nurse->ob_type)) {
> Py_INCREF(Py_None);
> return Py_None;
> }
>
> at the beginning of function make_nurse_and_patient would do the trick
for
> me. Would
> this be possible ?

No, not that; it wouldn't be the right fix, since code which expects to be
able to keep the originator alive but gets an object which doesn't support
weak refs needs to get a Python exception rather than a crash.

However, we /could/ check explicitly for None, since that's going to stay
alive no matter what we do.
I think in the case that's failing for you, both the nurse and patient
parameters in make_nurse_and_patient are PyNone, right?

> This brings me to a second point, it seems that life_support_dealloc is
> never called.
> If it would,
> the tp_free would be called for self, which is not initialized ie a NULL
> function pointer.

Really? Hmm, I'm not sure about that. Which fields in an extension type are
filled in automatically by Python and when they're called remains a little
mysterious to me, I have to admit.





More information about the Cplusplus-sig mailing list