2010-07-27 274 views
13

我有一個創建對象(類A的實例)的庫,並將它們傳遞給應該能夠調用其方法的python程序。將C++類實例傳遞給python並使用boost :: python

基本上我有C++類實例,我想從Python使用它們。偶爾該對象應該傳回給C++進行一些操作。

我創建了下面的封裝文件(讓我們假設New功能某處在C++代碼中調用):

#include <boost/python.hpp> 
#include <iostream> 
#include <boost/smart_ptr.hpp> 

using namespace boost; 
using namespace boost::python; 

int calls = 0; 

struct A 
{ 
    int f() { return calls++; } 
    ~A() { std::cout << "destroyed\n"; } 
}; 

shared_ptr<A> existing_instance; 

void New() { existing_instance = shared_ptr<A>(new A()); } 

int Count(shared_ptr<A> a) { return a.use_count(); } 

BOOST_PYTHON_MODULE(libp) 
{ 
    class_<A>("A") 
     .def("f", &A::f) 
    ; 

    def("Count", &Count); 

    register_ptr_to_python< shared_ptr<A> >(); 
} 

代碼缺少其中蟒蛇得到existing_instance的一部分。我沒有粘貼,但我們只是說我爲此使用了回調機制。

此代碼的工作,但我有幾個問題:

  1. 在計數功能(和所有其他C++操作函數)是精細傳遞a一樣,或者最好是像做const shared_ptr<A>& ?在我在python boost文檔中找到的代碼片段中,經常使用該引用,但我不瞭解其中的差別(當然,除了具有較高的引用計數器外)。

  2. 此代碼是否「安全」?當我將existing_instance傳遞給python時,它的計數器會增加(只是一次,即使在python中,我也會創建更多的對象副本),所以沒有辦法讓C++代碼可以銷燬對象,只要python成立至少一個「複製」。我對麼?我試圖玩弄指針,似乎我是正確的,我只是想確定一下。

  3. 我想阻止python創建實例A.他們應該只能從C++代碼傳遞。我怎麼能做到這一點? 編輯:發現,我只需要使用NO_INIT和不可複製:class_<A, boost::noncopyable>("A", no_init)

回答

14

boost::python知道所有關於boost::shared_ptr,但你需要告訴它boost::shared_ptr<A>持有A一個實例,您可以通過在模板參數列表中添加boost::shared_ptr<A>class_做到這一點,在這個「舉行類型」的更多信息是here in the boost documentation

爲了防止情況下被蟒蛇創建,添加boost::python::no_init到class_的構造函數,所以你最終:

boost::python::class_< A, boost::shared_ptr<A> >("A", boost::python::no_init) 
    //... .def, etc 
    ; 

一般你不應該通過引用傳遞圍繞共享指針,因爲如果對共享指針的引用無效,則共享指針指向的引用也被無效(因爲引用共享指針時不會將引用計數器遞增到指向的對象)。

將對象周圍的boost::shared_ptr對象傳入或傳出python是完全安全的,只要您不更改return_value_policy,引用計數(python和shared_ptr)將被正確管理。如果你改變了暴露在python中的方法的策略,以便它返回對共享指針的引用,那麼你可能會導致問題,就像通過C++引用傳遞共享指針可能會導致問題一樣。

(。此外,你應該使用make_shared<A>(...)優先於shared_ptr<A>(new A(...))

+0

什麼之間的區別(實際上) 「class_ (」 A 「NO_INIT)」 和「提升: :python :: class_ >(「A」,boost :: python :: no_init)「? 即使沒有在「class_」之後指定「boost :: shared_ptr 」,我發佈的代碼仍然完美。那麼,爲什麼我需要這個? – Emiliano 2010-08-01 16:27:33

+0

它指定了實際上由python「A」包裝的默認類型 - 所以如果你有一個C++函數返回一個'A','A *'shared_ptr或者類似的東西,並且暴露給python,那麼返回值將被保存爲shared_ptr - 如果您經常將這些對象傳入或傳出python,那麼它將會被正確處理。 有關更多信息,請參見http://www.boost.org/doc/libs/1_43_0/libs/python/doc/v2/class.html#HeldType(尤其是第2點)。 – James 2010-08-01 17:32:46

1

在這種情況下我的代碼看起來像這樣(爲你的例子):

... 

BOOST_PYTHON_MODULE(libp) 
{ 
    class_<A, boost::shared_ptr<A>, boost::noncopyable >("A") 
     .def("f", &A::f) 
     .def("Count", &Count) 
    ; 
} 

它禁止是非常重要的boost :: python來複制東西,但是如果你使用 shared_ptr的機會是你只需要在幾個受控的情況下複製。

相關問題