2010-07-27 24 views
13

Nesneleri (A sınıfı örneklerini) oluşturan ve bunları yöntemlerini çağırabilmesi gereken bir python programına ileten bir kitaplığım var.C++ sınıf örneklerini python'a yükseltmek :: python

Temel olarak C++ sınıf örneklerine sahibim ve bunları python'dan kullanmak istiyorum. Bazen bu nesne bazı manipülasyonlar için C++ 'ya geri geçirilmelidir.

#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> >(); 
} 

kod piton existing_instance alır kısmından yoksundur:

aşağıdaki sarıcı dosyası (en New işlevi yerde C++ kodunda denir varsayalım) oluşturuldu. Bunu eklemedim, ama sadece bu amaçla bir geri çağırma mekanizması kullandığımı varsayalım.

Bu kod çalışır ama birkaç soru var: Sayım fonksiyonunda

  1. (ve diğer tüm C++ manipülasyon işlevlerinde) öyle a geçmek verildiği veya const shared_ptr<A>& böyle bir şey yapmak daha iyidir ? Python destek dökümantasyonunda bulduğum kod parçacıklarında referans sıklıkla kullanılır fakat farkı anlamıyorum (tabii ki daha yüksek bir referans sayacına sahip olmanın dışında).

  2. Bu kod "güvenli" midir? Var olan_instance'ı python'a aktardığımda, sayacı artar (sadece bir kere, pythonda olsa bile, nesnenin daha fazla kopyasını çıkarırsam), böylece C++ kodunun python'u tuttuğu sürece nesneyi yok edemez. en azından bir "kopya". Doğrumuyum? İşaretçilerle oynamayı denedim ve doğru gibi görünüyor, emin olmak için soruyorum.

  3. Python'un A'nın örneklerini oluşturmasını engellemek istiyorum. Bunlar yalnızca C++ kodundan geçirilmelidir. Bunu nasıl başarabilirim? DÜZENLEME: my kodu (sizin gibi) şu şekilde görünür Bu durumda class_<A, boost::noncopyable>("A", no_init)

cevap

14

boost::python tüm yaklaşık boost::shared_ptr bilir, ama sen boost::shared_ptr<A>A bir örneğini tutan anlatmamız gerek, sen class_ şablon argümanı listesinde boost::shared_ptr<A> ekleyerek yaparsınız, bu 'Held Type' üzerinde daha fazla bilgi here in the boost documentation olduğunu. ile sona böylece örneklerini engellemek için

piton gelen oluşturulan, sen class_ kurucusuna boost::python::no_init ekleyin:

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

genelsize olmamalı, referans olarak etrafında paylaşılan işaretçileri geçmesi beri eğer Paylaşılan işaretçi başvurusu geçersiz kılınır, ardından paylaşılan işaretçinin işaret ettiği referans da geçersiz hale getirilir (paylaşılan işaretçinin referansı referans sayacını işaret edilen nesneye artırmaz).

'u değiştirmemeniz koşuluyla, boost::shared_ptr nesnelerini python'a ve python'dan geçirmek kesinlikle güvenlidir, referans sayımları (python ve shared_ptr) doğru şekilde yönetilecektir. Paylaşılan bir işaretçiye bir başvuru döndürmesi için python'da açığa çıkarılan bir yöntemin ilkesini değiştirirseniz, sorunlara neden olabilirsiniz, C++ başvuruları tarafından paylaşılan göstergelerin aktarılması sorunlara neden olabilir.

(. Ayrıca, shared_ptr<A>(new A(...)) tercih için make_shared<A>(...) kullanmalıdır)

+0

arasındaki (uygulamada) ne fark "class_ (" A "no_init)" ve "boost: : python :: class_ > ("A", boost :: python :: no_init) "? Gönderdiğim kod, "class_" dan sonra "boost :: shared_ptr " belirtmeden bile mükemmel şekilde çalışır. O zaman neden buna ihtiyacım var? – Emiliano

+0

Aslında bir python 'A' tarafından sarılacak varsayılan tür belirtir - böylece bir 'A', 'A *' shared_ptr veya benzer bir şey döndüren bir C++ işleviniz varsa ve bunu python'a gösterdiyseniz Geri dönüş değeri, paylaşılan tüm paylar doğru bir şekilde işleneceğinden, sık sık bu nesneleri python içine ve dışına aktarıyorsanız, bir paylaşımlı_ptr olarak tutulacaktır. Daha fazla bilgi için http://www.boost.org/doc/libs/1_43_0/libs/python/doc/v2/class.html#HeldType (özellikle point 2) konusuna bakın. – James

1

:

... 

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

O korusun önemlidir bulundu, ben sadece no_init ve noncopyable kullanmak gerekir boost :: python bir şeyleri kopyalamak için, ama shared_ptr kullanma olasılığınız varsa, sadece birkaç kontrollü durumda kopyalama yapmanız gerekir.

İlgili konular