2013-12-14 18 views
20

का खुलासा कैसे करें मैं boost.python के लिए काफी नया हूं और एक फ़ंक्शन के रिटर्न वैल्यू को पाइथन में बेनकाब करने का प्रयास कर रहा हूं।Boost.Python: std :: unique_ptr

समारोह हस्ताक्षर इस तरह दिखता है:

std::unique_ptr<Message> someFunc(const std::string &str) const; 

जब अजगर में फ़ंक्शन कॉल, मैं निम्नलिखित त्रुटि मिलती है:

TypeError: No to_python (by-value) converter found for C++ type: std::unique_ptr<Message, std::default_delete<Message> > 

अजगर में मेरे समारोह कॉल इस तरह दिखता है:

a = mymodule.MyClass() 
a.someFunc("some string here") # error here 

मैंने std :: unique_ptr का पर्दाफाश करने की कोशिश की लेकिन इसे काम पर नहीं लाया .. क्या कोई जानता है कि पॉइंटर क्लास का सही तरीके से खुलासा कैसे किया जाए? धन्यवाद!

संपादित करें: मैं निम्नलिखित की कोशिश की:

class_<std::unique_ptr<Message, std::default_delete<Message>>, bost::noncopyable ("Message", init<>()) 

; 

इस उदाहरण को संकलित करता है, लेकिन मैं अभी भी त्रुटि ऊपर उल्लेख मिलता है। इसके अलावा, मैं वर्ग का पर्दाफाश करने के Message ही

class_<Message>("Message", init<unsigned>()) 

     .def(init<unsigned, unsigned>()) 
     .def("f", &Message::f) 
; 

उत्तर

14

संक्षेप में, बूस्ट। पायथन चाल-अर्थशास्त्र का समर्थन नहीं करता है, और इसलिए std::unique_ptr का समर्थन नहीं करता है। Boost.Python's news/change log का कोई संकेत नहीं है कि इसे C++ 11 move-semantics के लिए अपडेट किया गया है। इसके अतिरिक्त, unique_ptr समर्थन के लिए एक वर्ष से अधिक समय तक छुआ नहीं गया है।

फिर भी, बूस्ट। पायथन std::auto_ptr के माध्यम से पाइथन से किसी ऑब्जेक्ट के अनन्य स्वामित्व को स्थानांतरित करने का समर्थन करता है।

  • जब अजगर को सी ++ स्थानान्तरण स्वामित्व, सी ++ समारोह चाहिए::
      unique_ptr अनिवार्य रूप से auto_ptr के सुरक्षित संस्करण है, यह काफी सीधे आगे एक API auto_ptr का उपयोग करता है करने के लिए unique_ptr का उपयोग कर एक API अनुकूल करने के लिए किया जाना चाहिए
    • boost::python::return_value_policy के कॉलपॉली के साथ boost::python::manage_new_object परिणाम कनवर्टर के साथ खुलासा किया जाए।
    • release() के माध्यम से unique_ptr रिहाई नियंत्रण है और एक कच्चे सूचक
  • जब सी ++ के लिए अजगर स्थानान्तरण स्वामित्व, सी ++ समारोह चाहिए वापसी:
    • उदाहरण auto_ptr के माध्यम से स्वीकार करते हैं। FAQ का उल्लेख है कि manage_new_object नीति के साथ C++ से लौटाए गए पॉइंटर्स std::auto_ptr के माध्यम से प्रबंधित किए जाएंगे।

      /// @brief Mockup Spam class. 
      struct Spam; 
      
      /// @brief Mockup factory for Spam. 
      struct SpamFactory 
      { 
          /// @brief Create Spam instances. 
          std::unique_ptr<Spam> make(const std::string&); 
      
          /// @brief Delete Spam instances. 
          void consume(std::unique_ptr<Spam>); 
      }; 
      

      SpamFactory::make() और SpamFactory::consume() के माध्यम से लिपटे रहने की जरूरत है:

    • release()

एक API/पुस्तकालय बदला नहीं जा सकता है कि यह देखते हुए के माध्यम से एक unique_ptr को auto_ptr रिहाई नियंत्रण है सहायक कार्यों।

कार्य अजगर को C++ से स्वामित्व स्थानांतरित सामान्य रूप से एक समारोह है कि अजगर समारोह वस्तुओं बना दिया जाएगा, लिपटे जा सकता है:

/// @brief Adapter a member function that returns a unique_ptr to 
///  a python function object that returns a raw pointer but 
///  explicitly passes ownership to Python. 
template <typename T, 
      typename C, 
      typename ...Args> 
boost::python::object adapt_unique(std::unique_ptr<T> (C::*fn)(Args...)) 
{ 
    return boost::python::make_function(
     [fn](C& self, Args... args) { return (self.*fn)(args...).release(); }, 
     boost::python::return_value_policy<boost::python::manage_new_object>(), 
     boost::mpl::vector<T*, C&, Args...>() 
    ); 
} 

मूल कार्य करने के लिए लैम्ब्डा प्रतिनिधियों, और अजगर को उदाहरण के releases() स्वामित्व, और कॉल पॉलिसी इंगित करती है कि पाइथन लैम्ब्डा से लौटाए गए मूल्य का स्वामित्व लेगा। mpl::vector Boost.Python को कॉल हस्ताक्षर का वर्णन करता है, जो इसे भाषाओं के बीच फ़ंक्शन प्रेषण को व्यवस्थित करने की अनुमति देता है।

adapt_unique का परिणाम SpamFactory.make() के रूप में सामने आ रहा है:

boost::python::class_<SpamFactory>(...) 
    .def("make", adapt_unique(&SpamFactory::make)) 
    // ... 
    ; 

सामान्य रूप से अनुकूल SpamFactory::consume() एक और अधिक कठिन है, लेकिन यह बहुत आसान एक सरल सहायक समारोह लिखने के लिए है:

/// @brief Wrapper function for SpamFactory::consume_spam(). This 
///  is required because Boost.Python will pass a handle to the 
///  Spam instance as an auto_ptr that needs to be converted to 
///  convert to a unique_ptr. 
void SpamFactory_consume(
    SpamFactory& self, 
    std::auto_ptr<Spam> ptr) // Note auto_ptr provided by Boost.Python. 
{ 
    return self.consume(std::unique_ptr<Spam>{ptr.release()}); 
} 

सहायक समारोह मूल समारोह में प्रतिनिधियों, और auto_ptr को बूस्ट.पथन द्वारा प्रदान किए गए unique_ptr को एपीआई द्वारा आवश्यक रूपांतरित करता है।SpamFactory_consume सहायक समारोह SpamFactory.consume() के रूप में सामने आ रहा है:

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

/// @brief Mockup Spam class. 
struct Spam 
{ 
    Spam(std::size_t x) : x(x) { std::cout << "Spam()" << std::endl; } 
    ~Spam() { std::cout << "~Spam()" << std::endl; } 
    Spam(const Spam&) = delete; 
    Spam& operator=(const Spam&) = delete; 
    std::size_t x; 
}; 

/// @brief Mockup factor for Spam. 
struct SpamFactory 
{ 
    /// @brief Create Spam instances. 
    std::unique_ptr<Spam> make(const std::string& str) 
    { 
    return std::unique_ptr<Spam>{new Spam{str.size()}}; 
    } 

    /// @brief Delete Spam instances. 
    void consume(std::unique_ptr<Spam>) {} 
}; 

/// @brief Adapter a non-member function that returns a unique_ptr to 
///  a python function object that returns a raw pointer but 
///  explicitly passes ownership to Python. 
template <typename T, 
      typename ...Args> 
boost::python::object adapt_unique(std::unique_ptr<T> (*fn)(Args...)) 
{ 
    return boost::python::make_function(
     [fn](Args... args) { return fn(args...).release(); }, 
     boost::python::return_value_policy<boost::python::manage_new_object>(), 
     boost::mpl::vector<T*, Args...>() 
    ); 
} 

/// @brief Adapter a member function that returns a unique_ptr to 
///  a python function object that returns a raw pointer but 
///  explicitly passes ownership to Python. 
template <typename T, 
      typename C, 
      typename ...Args> 
boost::python::object adapt_unique(std::unique_ptr<T> (C::*fn)(Args...)) 
{ 
    return boost::python::make_function(
     [fn](C& self, Args... args) { return (self.*fn)(args...).release(); }, 
     boost::python::return_value_policy<boost::python::manage_new_object>(), 
     boost::mpl::vector<T*, C&, Args...>() 
    ); 
} 

/// @brief Wrapper function for SpamFactory::consume(). This 
///  is required because Boost.Python will pass a handle to the 
///  Spam instance as an auto_ptr that needs to be converted to 
///  convert to a unique_ptr. 
void SpamFactory_consume(
    SpamFactory& self, 
    std::auto_ptr<Spam> ptr) // Note auto_ptr provided by Boost.Python. 
{ 
    return self.consume(std::unique_ptr<Spam>{ptr.release()}); 
} 

BOOST_PYTHON_MODULE(example) 
{ 
    namespace python = boost::python; 
    python::class_<Spam, boost::noncopyable>(
     "Spam", python::init<std::size_t>()) 
    .def_readwrite("x", &Spam::x) 
    ; 

    python::class_<SpamFactory>("SpamFactory", python::init<>()) 
    .def("make", adapt_unique(&SpamFactory::make)) 
    .def("consume", &SpamFactory_consume) 
    ; 
} 

इंटरएक्टिव पायथन:

>>> import example 
>>> factory = example.SpamFactory() 
>>> spam = factory.make("a" * 21) 
Spam() 
>>> spam.x 
21 
>>> spam.x *= 2 
>>> spam.x 
42 
>>> factory.consume(spam) 
~Spam() 
>>> spam.x = 100 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
Boost.Python.ArgumentError: Python argument types in 
    None.None(Spam, int) 
did not match C++ signature: 
    None(Spam {lvalue}, unsigned int) 
+0

विस्तृत उत्तर के लिए बहुत बहुत धन्यवाद! मैं इसे जल्द से जल्द कोशिश करूँगा, लेकिन कोड अच्छा दिखता है! – schlimpf

+0

और std :: unique_ptr के बारे में क्या है जिसे add_property के रूप में परिभाषित किया गया है। क्या मुझे इसे क्लास परिभाषा पर लपेटना है, जहां मैं वास्तव में संपत्ति जोड़ रहा हूं या_python_converter को परिभाषित करना बेहतर अभ्यास होगा? –

3

मेरे सुझाव get() साथ std::unique_ptr कंटेनर से कच्चे सूचक प्राप्त करने के लिए कर रही है। आपको unique_ptr को पूरे समय के लिए सावधानी बरतनी होगी कि आप कच्चे सूचक मूल्य का उपयोग करना चाहते हैं, अन्यथा ऑब्जेक्ट हटा दिया जाएगा और आपके पास स्मृति के अमान्य क्षेत्र में एक सूचक होगा।

+0

आप एक छोटा सा उदाहरण कृपया जोड़ सकता है? – schlimpf

+1

इस 'auto return_value = class_ >, bost :: noncopyable ("message", init <>()); ' ' संदेश * msg_ptr = return_value.get(); ' – Nicole

+0

क्या यह कोड समझ में आता है? मुझे यह कहां रखना चाहिए? – schlimpf

-1

मुझे लगता है कि आजकल वहाँ आप क्या देख रहे हैं के लिए ... कारण यह है कि std::unique_ptr<Message> someFunc(const std::string &str) मूल्य, जिसका अर्थ है द्वारा लौटा रहा है ऐसा करने के लिए कोई रास्ता नहीं है दो चीजों में से एक:

  1. वापसी मान जा रहा है कॉपी किया जाना चाहिए (लेकिन unique_ptr is not copyable);
  2. वापसी मूल्य को स्थानांतरित करने जा रहा है (अब समस्या यह है कि बूस्ट :: पायथन अर्थशास्त्र को स्थानांतरित करने के लिए समर्थन प्रदान नहीं करता है)। (हे, मैं बूस्ट 1,53 का उपयोग कर रहा हूं, नवीनतम संस्करणों में निश्चित नहीं हूं);

क्या कुछ फनक() वस्तु बना रहा है? मामले में हाँ, मुझे लगता है कि समाधान नहीं एक आवरण बनाने के लिए, इस मामले में है, तो आप संदर्भ द्वारा लौट सकते हैं:

class_<std::unique_ptr<Message, std::default_delete<Message>>, boost::noncopyable>("unique_ptr_message") 
    .def("get", &std::unique_ptr<Message>::get, return_value_policy<reference_existing_object>()) 
; 

और भी कार्य::

std::unique_ptr<Message>& someFunc(const std::string &str) 

वर्ग का पर्दाफाश

def("someFunc", someFunc, return_value_policy<reference_existing_object>()); 
+0

दुर्भाग्य से मैं पुस्तकालय में कुछ भी नहीं बदल सकता। फ़ंक्शन ऑब्जेक्ट बना रहा है (यह ऑब्जेक्ट बनाता है जो एक और फ़ंक्शन कॉल कर रहा है) – schlimpf

1

बूस्ट movable semantics और unique_ptrsince v.1.55 का समर्थन करता है

boost::python::class_<SpamFactory>(...) 
    // ... 
.def("consume", &SpamFactory_consume) 
; 

यहां एक संपूर्ण कोड उदाहरण है। लेकिन मेरी परियोजना में मैं पिछले संस्करण का इस्तेमाल किया और इस तरह के सरल आवरण बनाया:

class_<unique_ptr<HierarchyT>, noncopyable>(typpedName<LinksT>("hierarchy", false) 
, "hierarchy holder") 
    .def("__call__", &unique_ptr<HierarchyT>::get, 
     return_internal_reference<>(), 
     "get holding hierarchy") 
    .def("reset", &unique_ptr<HierarchyT>::reset, 
     "reset holding hierarhy") 
    ; 

अजगर shierarchy रूप unique_ptr<HierarchyT> बना सकते हैं और यह समारोह है कि यह संदर्भ द्वारा स्वीकार करता है पारित करने के लिए।
अजगर कोड:

hier = mc.shierarchy() 
mc.clusterize(hier, nds) 

जहां सी ++ समारोह float clusterize(unique_ptr<HierarchyT>& hier,...) है।
तब तक पहुँचने के लिए अजगर में परिणाम एक फोन hier() unique_ptr से लिपटे वस्तु पाने के लिए करते हैं:

output(hier(), nds) 
संबंधित मुद्दे