2010-07-27 7 views
13

मेरे पास एक लाइब्रेरी है जो ऑब्जेक्ट्स (कक्षा ए के उदाहरण) बनाती है और उन्हें एक पायथन प्रोग्राम में पास करती है जो उनके तरीकों को कॉल करने में सक्षम होना चाहिए।सी ++ कक्षाओं के उदाहरणों को बढ़ावा देने के साथ पाइथन को पास करना :: पायथन

असल में मेरे पास सी ++ वर्ग के उदाहरण हैं और मैं उन्हें अजगर से उपयोग करना चाहता हूं। कभी-कभी उस वस्तु को कुछ जोड़ों के लिए सी ++ में वापस भेज दिया जाना चाहिए।

#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 हो जाता है का अभाव:

मैं निम्नलिखित आवरण फ़ाइल (मान लेते हैं कि New समारोह सी ++ कोड में कहीं भी कहा जाता है भी नहीं) बनाया। मैंने इसे पेस्ट नहीं किया, लेकिन आइए बस यह कहें कि मैं उस उद्देश्य के लिए कॉलबैक तंत्र का उपयोग करता हूं।

इस कोड काम करता है लेकिन मैं कुछ प्रश्न हैं:

  1. गणना समारोह में (और अन्य सभी सी ++ हेरफेर कार्यों में) यह a ऐसे ही पारित करने के लिए ठीक है या यह const shared_ptr<A>& की तरह कुछ करने के लिए बेहतर है ? पाइथन बूस्ट प्रलेखन में मिले कोड स्निपेट में संदर्भ अक्सर उपयोग किया जाता है लेकिन मुझे अंतर नहीं समझता है (बेशक उच्च संदर्भ काउंटर होने के अलावा)।

  2. क्या यह कोड "सुरक्षित" है? जब मैं मौजूदा_इंस्टेंस को पायथन पर पास करता हूं, तो उसका काउंटर बढ़ जाएगा (केवल एक बार, अगर पाइथन में भी मैं ऑब्जेक्ट की अधिक प्रतियां बना देता हूं) तो कोई तरीका नहीं है कि सी ++ कोड वस्तु को नष्ट कर सकता है जहां तक ​​पाइथन धारण करता है कम से कम एक "प्रतिलिपि"। क्या मैं सही हूँ? मैंने पॉइंटर्स के साथ खेलने की कोशिश की और ऐसा लगता है कि मैं सही हूं, मैं बस सुनिश्चित करने के लिए कह रहा हूं।

  3. मैं अजगर के उदाहरण बनाने से पाइथन को रोकना चाहता हूं। उन्हें केवल सी ++ कोड से ही पारित किया जाना चाहिए। मैं इसे कैसे प्राप्त कर सकता हूं? संपादित: class_<A, boost::noncopyable>("A", no_init)

उत्तर

14

boost::python सब जानता है के बारे में boost::shared_ptr, लेकिन आप इसे बताने के लिए कि boost::shared_ptr<A>A का एक उदाहरण रखती है की जरूरत है, तो आप class_ करने के लिए टेम्पलेट तर्क सूची में boost::shared_ptr<A> जोड़कर ऐसा करते हैं, इस 'आयोजित प्रकार' पर अधिक जानकारी के here in the boost documentation है।

उदाहरणों को रोकने के लिए अजगर से बनाया जा रहा है, तो आप class_ निर्माता को boost::python::no_init जोड़ने के लिए, ताकि आप के साथ अंत:

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

में सामान्य आपको चाहिए नहीं, संदर्भ द्वारा साझा चारों ओर संकेत पारित के बाद से अगर साझा सूचक का संदर्भ अमान्य है, फिर जिस संदर्भ को साझा सूचक इंगित कर रहा है वह भी अमान्य है (क्योंकि साझा पॉइंटर का संदर्भ लेने से ऑब्जेक्ट की ओर इशारा करते हुए संदर्भ काउंटर नहीं बढ़ता है)।

यह पूरी तरह से करने के लिए और अजगर से चारों ओर boost::shared_ptr वस्तुओं पारित करने के लिए सुरक्षित है, संदर्भ मायने रखता है (अजगर और shared_ptr) सही ढंग से प्रदान की प्रबंधित किया जाएगा आप return_value_policy नहीं बदलते। यदि आप अजगर में उजागर की गई विधि की नीति को बदलते हैं ताकि वह किसी साझा सूचक के संदर्भ को वापस कर सके, तो आप समस्याएं पैदा कर सकते हैं, जैसे सी ++ संदर्भों के आस-पास साझा पॉइंटर्स पास करने से समस्याएं हो सकती हैं।

(। इसके अलावा, आप make_shared<A>(...) वरीयता में shared_ptr<A>(new A(...)) का उपयोग करना चाहिए)

+0

के बीच का अंतर (व्यवहार में) क्या है "class_ <एक, को बढ़ावा देने :: noncopyable> ('ए', no_init)" और "बढ़ावा: : पायथन :: class_ <ए, बूस्ट :: shared_ptr > ("ए", बूस्ट :: पायथन :: no_init) "? मेरे द्वारा पोस्ट किया गया कोड "class_" के बाद "boost :: shared_ptr " निर्दिष्ट किए बिना पूरी तरह से काम करता है। तो मुझे इसकी आवश्यकता क्यों होगी? – Emiliano

+0

यह डिफ़ॉल्ट प्रकार निर्दिष्ट करता है जो वास्तव में एक पायथन 'ए' द्वारा लपेटा जाएगा - इसलिए यदि आपके पास एक सी ++ फ़ंक्शन है जो 'ए', 'ए *' साझा_ptr या कुछ भी समान देता है, और इसे पायथन पर बेनकाब करता है, तो वापसी मूल्य को shared_ptr के रूप में आयोजित किया जाएगा - यदि आप चाहते हैं कि आप अक्सर इन वस्तुओं को पाइथन में और बाहर से गुजर रहे हैं, क्योंकि सभी स्वामित्व सही ढंग से संभाले जाएंगे। अधिक जानकारी के लिए http://www.boost.org/doc/libs/1_43_0/libs/python/doc/v2/class.html#HeldType (esp। Point 2) देखें। – James

1

इस स्थिति में मेरे कोड इस प्रकार दिखाई देगा (आपके उदाहरण के लिए):

... 

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

यह ना करे के लिए महत्वपूर्ण है पाया, मैं सिर्फ no_init और noncopyable उपयोग करने की आवश्यकता boost :: python चीजों की प्रतिलिपि बनाने के लिए, लेकिन यदि आप साझा_ptr का उपयोग कर रहे हैं तो संभावना है कि आपको केवल कुछ नियंत्रित स्थितियों में प्रतिलिपि बनाने की आवश्यकता है।