Hi I don't know if something like this has been discussed before, but I thought I'd contribute it in case it is useful.
I found that with_custodian_and_ward didn't suit my needs, because (a) the association it creates is permanent, even if the underlying association is later broken, leading to handle leaks; (b) I had some issues with destructor ordering when the interpreter exits (sorry, I don't recall the details). I've created an alternative call policy that requires a wrapper custodian class with a handle<> data member, which is set to a reference to the ward object. This is suitable for wrapping functions that set an underlying C++ reference in the custodian, replacing any previous reference rather than adding to it. The code is below - I've only written a _postcall version, but it should be possible to write a non-postcall version too. At the moment it is part of a GPLv3+ project, but I'm working on getting permission from my employer to release this code under the Boost License as well, to make it easier to use in other Boost.Python-based projects (or to incorporate into Boost.Python itself). You can see it in action in spead2 (e.g. https://github.com/ska-sa/spead2/blob/v0.3.0/src/py_send.cpp). template<typename T, boost::python::handle<> T::*handle_ptr, std::size_t custodian, std::size_t ward, class BasePolicy_ = boost::python::default_call_policies> struct store_handle_postcall : BasePolicy_ { static_assert(custodian != ward, "object must not hold reference to itself"); static PyObject* postcall(PyObject *args, PyObject *result) { std::size_t arity = PyTuple_GET_SIZE(args); if (custodian > arity || ward > arity) { PyErr_SetString(PyExc_IndexError, "store_handle_postcall: argument index out of range"); return nullptr; } result = BasePolicy_::postcall(args, result); if (result == nullptr) return nullptr; PyObject *owner = custodian > 0 ? PyTuple_GET_ITEM(args, custodian - 1) : result; PyObject *child = ward > 0 ? PyTuple_GET_ITEM(args, ward - 1) : result; boost::python::extract<T &> extractor(owner); try { T &target = extractor(); target.*handle_ptr = boost::python::handle<>(boost::python::borrowed(child)); } catch (boost::python::error_already_set) { Py_XDECREF(result); return nullptr; } return result; } }; Bruce -- Bruce Merry Senior Science Processing Developer SKA South Africa _______________________________________________ Cplusplus-sig mailing list Cplusplus-sig@python.org https://mail.python.org/mailman/listinfo/cplusplus-sig