I have next class (it was simplified):
class Value { public: Value(); ~Value(); void setValue(int value); void setValue(double value); }
I have python boost module:
#include <boost/python.hpp> #include <boost/python/suite/indexing/vector_indexing_suite.hpp> #include <boost/python/suite/indexing/map_indexing_suite.hpp> BOOST_PYTHON_MODULE(py_classes) { typedef std::vector<Value> VectorClass; boost::python::type_info infoVectorValue = boost::python::type_id<VectorClass>(); const boost::python::converter::registration* regVectorValue = boost::python::converter::registry::query(infoVectorValue); if (regVectorValue == NULL || (*regVectorValue).m_to_python == NULL) { class_<VectorClass>("std_vector_value") .def(vector_indexing_suite<VectorClass>()); } }
Python script is called from dll library and uses container from pyd py_classes
. When dll-library is called first time std_vector_value
type is used without any problems.
When I reload dll-library inside executable I get next warning:
RuntimeWarning: to-Python converter for class boost::python::detail::container_element<class std::vector<class Value,class std::allocator<class Value> >, unsigned __int64,class boost::python::detail::final_vector_derived_policies <class std::vector<class Value, class std::allocator<class Value> >,0> > already registered; second conversion method ignored. return f(*args, **kwds)
So, it means:
- When dll-library is loaded first time, to-python converter is registered normally and python script can use
std_vector_value
type. - When dll-library is reloaded (
FreeLibrary
andLoadLibrary
functions), to-python converter trying to register one more time and checking if it was registered says that it has been already registered, but I can’t usestd_vector_value
type from python.
And this situation appears only for container classes (if I use std::vector
or std::map
– generally if I use vector_indexing_suite
or map_indexing_suite
), for class Value this warning doesn’t appear.
What am I doing wrong?
Advertisement
Answer
Problem was next: boost python was loaded from one exe-process, but by different DLL-libraries. It means I had 3 DLL-libraries that executed python scripts.
Python boost types worked without any problem until DLL-libraries were reloaded (calling FreeLibrary and LoadLibrary inside process without process relaunching).
Python boost has static variable register
(register is the name of this variable) stores references to python boost types.
When executable is launched, references to types are added to the static variable register
.
So, this check works normally:
boost::python::type_info infoVectorValue = boost::python::type_id<VectorClass>(); const boost::python::converter::registration* regVectorValue = boost::python::converter::registry::query(infoVectorValue); if (regVectorValue == NULL || (*regVectorValue).m_to_python == NULL) {
But when DLL-libraries are unloaded, references to these python boost types are left inside the static variable register
and they lead to DLL-library addresses that were freed. It means when library is loaded again, types checking gets reference for needed type (VectorClass
in my example) without problems, but this reference has already broken.
So, the solution for this problem is to link boost python library statically to each DLL-library – each DLL-library has it’s own static variable register
and boost python types
references are created for each DLL-library and when DLL-library is unloaded, register
variable is destroyed for this DLL.