Thanks for the reply, and apologies for the delay in mine; I've been
struggling with classes having protected destructors. Sorted now though..
On Sat, 23 Mar 2013 03:02:58 -0000, Niall Douglas
<s_sourcefo...@nedprod.com> wrote:
Separate C++ objects from their python wrappers. Have C++ objects
held by shared_ptr.
Have a custom deleter on shared_ptr invoke a virtual
int_PythonIsAboutToDelete() function before it actually calls delete.
You see as soon as destruction begins, all virtual functions cease to
work, so you need a predestructor stage.
This seems to be on the right track. I had some success when calling a
Python-exposed __del__ method, with std::auto_ptr<Environment> as
argument. I had found - with lots of printf calls - that the C++
destructor was being called twice. Each time, it called
pthread_mutex_destroy, and being one too many times, that caused a
seg-fault. Seemed like an ownership problem, and calling 'release' on
std::auto_ptr<Environment>, in the exposed "__del__" method, got around
that seg-fault, running without error.
I was in the middle of replying with a success story, but on further
testing, it seemed that this solution only worked when the library was
linked against libpython3 / libboost_python3. When linking against the
version 2.7 counterparts, seg-faults crept back in... I couldn't
understand why...
With that partial success, I thought that I should define a corresponding
__new__ method, to allocate the memory for the object deleted by __del__.
Although that seems okay to me in principal, I'm completely failing to
write a successful implementation...
Are there any boost python helpers for this? Again, any help greatly
appreciated!
// wrapper class
namespace mylib {
class IEnvironment
: public notmylib::Environment
{
IEnvironment(const boost::python::list& envp);
~IEnvironment(void) {}
// method implementing __new__ functionality?
static boost::shared_ptr<IEnvironment> Create(
boost::python::object type,
const boost::python::list *envp );
}
// custom deleter
void DelEnvironment(boost::shared_ptr<IEnvironment> env);
// pointer to start of environment array
char** m_envp;
// thread and gil state vars
PyThreadState * _save;
PyGILState_STATE gil_state;
}
// First function to be called in initialisation chain.
const char* const* mylib::IEnvironment::InitEnvironment(const
boost::python::list& envp)
{
int envc = boost::python::len(envp);
pylib::m_envp = new char*[envc+1];
stl_input_iterator<char*> begin(envp) end;
int i=0;
while ( begin != end )
{
pylib::m_envp[i++] = (*begin);
begin++;
}
pylib::m_envp[i] = '\0';
pylib::gil_state = PyGILState_Ensure();
pylib::_save = PyEval_SaveThread();
return &pylib::m_envp[0];
}
// Defines initialiser chain. The function body here runs last.
mylib::IEnvironment::IEnvironment(const boost::python::list& envp)
: Environment(InitIEnvironment(boost::ref(envp)))
{
PyEval_RestoreThread(pylib::_save);
PyGILState_Release(pylib::gil_state);
}
// attempt at writing a __new__ method
boost::shared_ptr<mylib::Environment> mylib::Environment::Create(
boost::python::object cls, const boost::python::list& envp )
{
PyTypeObject* cls_type = (PyTypeObject*)cls.ptr();
PyObject* cls_inst = PyType_GenericNew( cls_type, envp.ptr(),
Py_None);
if (PyType_Ready(cls_type) != 0)
{
throw error_already_set();
}
// lots of trial and error here. Always in error, so far...
return boost::make_shared<pylib::IEnvironment>(
boost::python::extract<pylib::IEnvironment>(
boost::python::object(boost::python::ptr(cls_inst))));
}
BOOST_PYTHON_MODULE(foo)
{
boost::python::class_<mylib::Environment, boost::noncopyable,
boost::shared_ptr<mylib::IEnvironment>
("Environment", init<const boost::python::list&>() )
.def("__new__", &mylib::IEnvironment::Create )
.staticmethod("__new__") //< necessary?
.def("__del__", &pylib::DelEnvironment )
;
}
Do your pre destruction cleanup like destroying mutexs in that
virtual function. Or indeed anything which can throw exceptions,
because destructors are (soon to be) noexcept.
Hope that helps,
Niall
Yep, thanks!
Cheers,
Alex
--
Using Opera's mail client: http://www.opera.com/mail/
_______________________________________________
Cplusplus-sig mailing list
Cplusplus-sig@python.org
http://mail.python.org/mailman/listinfo/cplusplus-sig