在我的應用程序中嵌入python時,我遇到了與python對象生存期有關的問題。我的應用程序使用虛擬方法將一些類擴展爲python,因此它們可以通過python代碼派生和擴展。應用程序使用python解釋器並調用對象的虛擬方法。問題是當對象的引用計數器在從C++代碼調用的python覆蓋方法內達到零時,解釋器立即銷燬對象。所以,如果我們在另一個對象方法中調用這樣的方法,我們將得到相當於的行爲,刪除這個聲明。簡單的測試代碼:Boost :: python:對象在重載方法中銷燬本身
對象:
class Base
{
public:
virtual ~Base()
{
std::cout << "C++ deleted" << std::endl;
std::cout.flush();
}
virtual void virtFunc()
{
}
void rmFunc()
{
std::cout << "Precall" << std::endl;
virtFunc();
std::cout << "Postcall" << std::endl;
//Segfault here, this doesn't exists.
value = 0;
}
private:
int value;
};
的boost :: Python模塊庫:
#include <boost/python.hpp>
#include <list>
#include "Types.h"
#include <iostream>
// Policies used for reference counting
struct add_reference_policy : boost::python::default_call_policies
{
static PyObject *postcall(PyObject *args, PyObject *result)
{
PyObject *arg = PyTuple_GET_ITEM(args, 0);
Py_INCREF(arg);
return result;
}
};
struct remove_reference_policy : boost::python::default_call_policies
{
static PyObject *postcall(PyObject *args, PyObject *result)
{
PyObject *arg = PyTuple_GET_ITEM(args, 0);
Py_DecRef(arg);
return result;
}
};
struct BaseWrap: Base, boost::python::wrapper<Base>
{
BaseWrap(): Base()
{
}
virtual ~BaseWrap()
{
std::cout << "Wrap deleted" << std::endl;
std::cout.flush();
}
void virtFunc()
{
if (boost::python::override f = get_override("virtFunc"))
{
try
{
f();
}
catch (const boost::python::error_already_set& e)
{
}
}
}
void virtFunc_()
{
Base::virtFunc();
}
};
std::list<Base*> objects;
void addObject(Base *o)
{
objects.push_back(o);
}
void removeObject(Base *o)
{
objects.remove(o);
}
BOOST_PYTHON_MODULE(pytest)
{
using namespace boost::python;
class_<BaseWrap, boost::noncopyable>("Base", init<>())
.def("virtFunc", &Base::virtFunc, &BaseWrap::virtFunc_);
def("addObject", &addObject, add_reference_policy());
def("removeObject", &removeObject, remove_reference_policy());
}
應用,與模塊鏈接:
#include <boost/python.hpp>
#include <list>
#include "Types.h"
extern std::list<Base*> objects;
int main(int argc, char **argv)
{
Py_Initialize();
boost::python::object main_module = boost::python::import("__main__");
boost::python::object main_namespace = main_module.attr("__dict__");
try
{
boost::python::exec_file("fail-test.py", main_namespace);
}
catch(boost::python::error_already_set const &)
{
PyErr_Print();
}
sleep(1);
objects.front()->rmFunc();
sleep(1);
}
fail-test.py:
import pytest
class Derived(pytest.Base):
def __init__(self, parent):
pytest.Base.__init__(self)
pytest.addObject(self)
def __del__(self):
print("Python deleted")
def virtFunc(self):
pytest.removeObject(self)
o1 = Derived(None)
o1 = None
輸出:
Precall
Python deleted
Wrap deleted
C++ deleted
Postcall
是否有避免這種行爲沒有什麼好的辦法?