이 작업은 boost::shared_ptr
과 Boost.Python의 일부 설정으로 수행 할 수 있습니다.
boost::shared_ptr
에는 사용자 지정 deleter를 허용하는 생성자가 있습니다. shared_ptr
의 참조 횟수가 0에 도달하면 shared_ptr
은 이전에 관리 된 포인터를 인수로 전달하여 고객 삭제자를 호출합니다. 이렇게하면 "no-op"또는 wxWindow::Destroy()
을 호출하는 것과 같은 다른 할당 해제 전략을 사용할 수 있습니다. 파이썬 클래스를 노출하는 경우 유형은 HeldType
를 통해 관리 할 수 있도록
class window {};
void no_op(window*) {};
boost::shared_ptr(new window(), &no_op);
은, Boost.Python이 있습니다. 이 경우 HeldType
은 boost::shared_ptr
이됩니다. 이를 통해 C++과 Python 사이에서 적절한 참조 계산이 가능하며 사용자 정의 할당 취소 전략이 허용됩니다.
- 억제 Boost.Python 기본 초기화 (
__init__
를) 만들 수 :는 boost::python::class_<window, boost::shared_ptr<window>, ...>("Window", ...);
이 투명하게 함께 일을 얻기에 간계는 것입니다.
- 사용자 정의 삭제자를 사용하여
shared_ptr
을 반환하는 팩토리 함수를 호출하는 __init__
함수를 명시 적으로 제공하십시오. 여기
만 destroy()
부재 기능을 파괴하고자하는 업 조롱 window
클래스이다. 참조를 생성하는 팩토리 함수 정의
class window
{
...
private:
~window();
public:
void destroy();
};
커스텀 Deleter가 함께 window
객체를 세었다. 커스텀 Deleter는 참조 카운트가 0에 도달했을 때 객체에 destroy()
을 호출합니다.
boost::shared_ptr<window> create_window()
{
return boost::shared_ptr<window>(
new window(),
boost::mem_fn(&window::destroy));
}
마지막으로 부스트를 사용하십시오.Python은 window
클래스를 노출하지만 기본 이니셜 라이저는 표시하지 않고 투명하게 create_window
팩토리 함수로 바꿉니다. 여기
boost::python::class_<window, boost::shared_ptr<window>,
boost::noncopyable>("Window", python::no_init)
.def("__init__", python::make_constructor(&create_window));
는 완벽한 예입니다
#include <iostream>
#include <boost/mem_fn.hpp>
#include <boost/python.hpp>
#include <boost/shared_ptr.hpp>
/// @brief Mockup window class.
class window
{
public:
window(unsigned int id)
: id_(id)
{
std::cout << "window::window() " << id_ << std::endl;
}
void action() { std::cout << "window::action() " << id_ << std::endl; }
void destroy()
{
std::cout << "window::destroy() " << id_ << std::endl;
delete this;
}
private:
~window() { std::cout << "window::~window() " << id_ << std::endl; }
private:
unsigned int id_;
};
/// @brief Factory function that will create reference counted window
/// objects, that will call window::destroy() when the reference
/// count reaches zero.
boost::shared_ptr<window> create_window(unsigned int id)
{
return boost::shared_ptr<window>(
new window(id),
boost::mem_fn(&window::destroy));
}
BOOST_PYTHON_MODULE(example) {
namespace python = boost::python;
// Expose window, that will be managed by shared_ptr, and transparently
// constructs the window via a factory function to allow for a custom
// deleter.
python::class_<window, boost::shared_ptr<window>,
boost::noncopyable>("Window", python::no_init)
.def("__init__", python::make_constructor(&create_window))
.def("action", &window::action)
;
}
그리고 그것의 사용 :
>>> from example import Window
>>> w1 = Window(1)
window::window() 1
>>> w2 = Window(2)
window::window() 2
>>> w3 = Window(3)
window::window() 3
>>> del w2
window::destroy() 2
window::~window() 2
>>> w3 = None
window::destroy() 3
window::~window() 3
>>> w = w1
>>> del w1
>>> w.action()
window::action() 1
>>> w = None
window::destroy() 1
window::~window() 1
공지 사항 파이썬은 파이썬은 더 이상이 없습니다 일단 개체를 삭제하는 C++을 알리는 방법 인스턴스에 대한 참조 따라서이 시나리오에서 Python은 삭제 된 객체에 대해 상호 작용을 시도하지 않습니다. Object가 C++로 삭제 될 때 표현 된 걱정을 덜어주기를 바랍니다.
C++이 여전히 Python에서 활성화 된 객체를 삭제할 상황이 발생하면 opaque pointer을 사용하여 구현 클래스와 핸들 클래스를 분리하는 것이 좋습니다. 핸들 클래스는 호출을 전달하기 전에 연관된 구현 인스턴스가 삭제되었는지 검사하여 예외가 Python까지 던져 지도록합니다.
와우, 덕분에 좋은 아이디어가 많이 있습니다. return_value_policy reference_existing_object와 함께 객체를 반환하는 각 클래스에 대한 정적 팩토리 메서드를 만드는 다른 솔루션을 생각해 냈습니다. 그러나 당신의 해결책은 더 좋습니다. – Jonatan
나는 추상 클래스로이 접근법을 시도했지만 make_constructor가 작동하지 않는 것으로 나타났습니다. init <> 생성자를 사용하면 작동하지만, make_constructor를 사용하면 파이썬과 C++간에 앞뒤로 전달 될 때 가상 메소드의 구현이 손실됩니다. init <>로 사용자 정의 소멸자를 설정할 방법이 없기 때문에 항상 사용자 정의 소멸자가있는 shared_ptr에서 사용자 정의 shared_ptr 클래스를 파생 시켰습니다. 하지만 shared_ptr에서 파생 된 것이 확실하지는 않습니다. 어떻게 생각해? – Jonatan
'shared_ptr'에서 파생되는 것을 주저합니다. 개념적으로 비 다형성 방식으로 사용될 때는 괜찮습니다. 그러나 Boost.Python은'shared_ptr'에 대해 상당한 양의 메타 프로그래밍과 처리를 수행하므로 안전하다는 것을 확실히 말할 수는 없습니다. 원래의 문제는 객체 조각의 결과처럼 들립니다. Boost.Python 솔루션은 ['bases'] (http://www.boost.org/doc/libs/1_53_0/libs/python/doc/v2/class.html#bases-spec) 및 ['wrapper'] (http://www.boost.org/doc/libs/1_53_0/libs/python/doc/v2/wrapper.html)에 나와 있습니다. –