2013-02-21 85 views
22

स्थितिगतिशील रूप rethrowing आत्म परिभाषित सी ++ बड़ा घूँट

का उपयोग कर अजगर अपवाद के रूप में अपवाद मैं एक अजगर भाषा एक सी ++ बड़ा घूँट का उपयोग कर एपीआई के लिए बाध्यकारी बनाना चाहते हैं। कुछ एपीआई फ़ंक्शंस अपवाद फेंक सकते हैं।

std::exception 
    -> API::Exception 
    -> API::NetworkException 
     -> API::TimeoutException 
     -> API::UnreachableException 
    -> API::InvalidAddressException 

वांछित व्यवहार इस प्रकार है::

  1. सभी प्रकार के अपवाद आवरण के रूप में एक मिलान अजगर वर्ग होना चाहिए सी ++ आवेदन आत्म परिभाषित अपवाद के एक पदानुक्रम, इस उदाहरण की तरह है। ये रैपर वर्ग मान्य पायथन अपवाद होना चाहिए।

  2. API कॉल एक C++ अपवाद फेंकता है, यह पकड़ा होना चाहिए। इसी अजगर अपवाद (अर्थात पकड़ा C++ अपवाद के आवरण वर्ग) होना चाहिए फेंक दिया

  3. यह एक गतिशील प्रक्रिया होना चाहिए: अजगर अपवाद प्रकार, क्रम पर निर्णय लिया जाता है केवल पकड़ा C++ अपवाद के क्रम प्रकार के आधार पर। इस तरह, SWIG इंटरफ़ेस फ़ाइल में पूर्ण अपवाद पदानुक्रम का वर्णन करने की कोई आवश्यकता नहीं है।

समस्याओं और प्रश्नों

  1. आवरण वर्गों कोई अजगर अपवाद हैं।

    बड़ा घूँट सभी आत्म परिभाषित अपवाद के लिए आवरण वर्गों बनाता है (किसी अन्य वर्ग के लिए) की तरह है, इन कक्षाओं अपवाद अजगर नहीं कर रहे हैं। आधार अपवाद (उदाहरण में API::Exception) का आवरण Object बजाय BaseException, पायथन वर्ग जिनमें से अजगर में सभी अपवादों को लिया जाना चाहिए फैली हुई है।

    इसके अलावा, यह बड़ा घूँट एक माता पिता के वर्ग मैन्युअल रूप से जोड़ जाने के लिए संभव प्रतीत नहीं होता। नोट %typemap(javabase) के उपयोग के माध्यम से जावा के साथ SWIG का उपयोग करते समय यह संभव है (विवरण के लिए SWIG documentation देखें)।

  2. कैसे Python C API उपयोगकर्ता परिभाषित अपवाद फेंक कर सकते हैं?

    पायथन सी एपीआई से पाइथन अपवाद फेंकने का सबसे आम तरीका PyErr_SetString[reference] पर कॉल करके है। यह नीचे डेमो आवेदन में भी दिखाया गया है।

    लेकिन इस मानक (बिल्ट-इन) अजगर को छोड़कर केवल मामूली बात है, क्योंकि उन्हें संदर्भ अजगर सी एपीआई में वैश्विक चर [reference] में संग्रहीत हैं।

    मुझे पता है कि स्व-परिभाषित अपवादों के संदर्भ प्राप्त करने के लिए PyErr_NewException[reference] विधि है, लेकिन मुझे यह काम नहीं मिला।

  3. Python C API रनटाइम पर C++ प्रकार का मूल्यांकन कैसे कर सकता है और फिर नाम से संबंधित पायथन रैपर वर्ग का पता लगा सकता है?

    मुझे लगता है एक अजगर वर्ग अजगर सी एपीआई के reflection part के माध्यम से, कार्यावधि में नाम से खोजा जा सकता है। क्या यह जाने का रास्ता है? और यह अभ्यास में कैसे किया जाता है?

डेमो आवेदन

इस समस्या के साथ प्रयोग करने के लिए, मैं एक छोटे से सी ++ एपीआई एक भी समारोह है कि किसी संख्या का फ़ैक्टोरियल की गणना करता है के साथ बनाया। इसमें न्यूनतम आत्म-परिभाषित अपवाद पदानुक्रम है, जिसमें केवल एक वर्ग TooBigException शामिल है।

नोट करें कि यह अपवाद सामान्य समस्या में आधार अपवाद के रूप में कार्य करता है और एप्लिकेशन को इसके किसी भी उप-वर्ग के साथ काम करना चाहिए। इसका मतलब है कि समाधान केवल पाइथन (इसे नीचे देखें) में पुनर्स्थापित करने के लिए पकड़े गए अपवाद के गतिशील (यानी रनटाइम) प्रकार का उपयोग कर सकता है।

// File: numbers.h 
namespace numbers { 
int fact(int n); 
} 

// File: numbers.cpp 
#include "TooBigException.h" 
namespace numbers { 
int fact(int n) { 
    if (n > 10) throw TooBigException("Value too big", n); 
    else if (n <= 1) return 1; 
    else return n*fact(n-1); 
} 
} 

// File: TooBigException.h 
namespace numbers { 
class TooBigException: public std::exception { 
public: 
    explicit TooBigException(const std::string & inMessage, 
          const int inValue); 
    virtual ~TooBigException() throw() {} 
    virtual const char* what() const throw(); 
    const std::string & message() const; 
    const int value() const; 
private: 
    std::string mMessage; 
    int mValue; 
}; 
} 

// File: TooBigException.cpp 
#include "TooBigException.h" 
namespace numbers { 
TooBigException::TooBigException(const std::string & inMessage, const int inValue): 
    std::exception(), 
    mMessage(inMessage), 
    mValue(inValue) 
{ 
} 
const char* TooBigException::what() const throw(){ 
    return mMessage.c_str(); 
} 
const std::string & TooBigException::message() const { 
    return mMessage; 
} 
const int TooBigException::value() const { 
    return mValue; 
} 
} 

प्राप्त करने के लिए अजगर बाध्यकारी मैं निम्नलिखित बड़ा घूँट इंटरफ़ेस फ़ाइल का उपयोग:

// File: numbers.i 
%module numbers 
%include "stl.i" 
%include "exception.i" 

%{ 
#define SWIG_FILE_WITH_INIT 
#include "TooBigException.h" 
#include "numbers.h" 
%} 

%exception { 
    try { 
     $action 
    } 
    catch (const numbers::TooBigException & e) { 
     // This catches any self-defined exception in the exception hierarchy, 
     // because they all derive from this base class. 
     <TODO> 
    } 
    catch (const std::exception & e) 
    { 
     SWIG_exception(SWIG_RuntimeError, (std::string("C++ std::exception: ") + e.what()).c_str()); 
    } 
    catch (...) 
    { 
     SWIG_exception(SWIG_UnknownError, "C++ anonymous exception"); 
    } 
} 

%include "TooBigException.h" 
%include "numbers.h" 

तो एपीआई के लिए हर कॉल है

डेमो आवेदन के पूर्ण स्रोत कोड इस प्रकार है एक कोशिश-पकड़ ब्लॉक द्वारा लपेटा। हमारे मूल प्रकार के पहले अपवाद पकड़े और संभाले जाते हैं। फिर SWIG अपवाद लाइब्रेरी का उपयोग करके अन्य सभी अपवाद पकड़े जाते हैं और पुनर्स्थापित होते हैं।

नोट numbers::TooBigException में से किसी उपवर्ग पकड़ा है और उनके गतिशील की रैपर (अर्थात क्रम) टाइप फेंक दिया जाना चाहिए, न कि उनका स्थिर का आवरण (अर्थात समय संकलन) प्रकार है, जो हमेशा है TooBigException!

परियोजना एक लिनक्स मशीन पर निम्न आदेशों को क्रियान्वित करने से आसानी से बनाया जा सकता है:

$ swig -c++ -python numbers.i 
$ g++ -fPIC -shared TooBigException.cpp numbers.cpp numbers_wrap.cxx \ 
    -I/usr/include/python2.7 -o _numbers.so 

वर्तमान कार्यान्वयन

मेरे वर्तमान कार्यान्वयन अभी भी (सफलतापूर्वक) एक निश्चित मानक अजगर अपवाद फेंकता है।

PyErr_SetString(PyExc_Exception, (std::string("C++ self-defined exception ") + e.what()).c_str()); 
return NULL; 

कौन सा अजगर में निम्नलिखित (उम्मीद) व्यवहार देता है:: कोड ऊपर <TODO> तो ले लेती है

>>> import numbers 
>>> fact(11) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
Exception: C++ self-defined exception Value too big 
+1

मुझे सच में यकीन नहीं है कि आप क्या चाहते हैं, लेकिन क्या आपने देखा है कि यह कोड आपके दूसरे मामले में मदद करता है या नहीं? 'फेंक;' – PlasmaHH

उत्तर

9

ऐसा लगता है कि किसी को बड़ा घूँट-उपयोगकर्ता सूची पर पर अपने बुनियादी सवाल का जवाब है ...

%exception { 
    try { 
    $action 
    } catch (MyException &_e) { 
    SWIG_Python_Raise(SWIG_NewPointerObj(
      (new MyException(static_cast<const MyException& >(_e))), 
      SWIGTYPE_p_MyException,SWIG_POINTER_OWN), 
     "MyException", SWIGTYPE_p_MyException); 
    SWIG_fail; 
    } 
} 

यह आपको अपनी अपवाद कक्षाओं के लिए रैपर जेनरेट किया है मान करता है, मेरा मानना ​​है कि।अपने पदानुक्रम के लिए

+0

यह वास्तव में यह करता है। शर्म ओपी ने आपका जवाब स्वीकार नहीं किया। – wombat

+1

यह वास्तव में उत्तर का हिस्सा है। हालांकि, जैसा कि प्रश्न में स्पष्ट रूप से बताया गया है, मैं _dynamic_ प्रकार का उपयोग करना चाहता हूं, जबकि यह समाधान एक स्थैतिक कलाकार करता है। दूसरे शब्दों में: MyException के किसी भी उप-वर्ग को पकड़ा जाएगा और एक MyException में बदल दिया जाएगा और सभी सबक्लास जानकारी खो जाती है। – tbacker

5

उदाहरण

std::exception 
    -> API::Exception 
    -> API::NetworkException 
     -> API::TimeoutException 
     -> API::UnreachableException 
    -> API::InvalidAddressException 

example.i:

%module example 
%include "stl.i" 
%include "exception.i" 

%{ 
#define SWIG_FILE_WITH_INIT 
#include "example.cpp" 
%} 

%{ 

#define CATCH_PE(Namespace,Exception) \ 
    catch(const Namespace::Exception &e) \ 
    { \ 
     SWIG_Python_Raise(SWIG_NewPointerObj(new Namespace::Exception(e), \ 
      SWIGTYPE_p_##Namespace##__##Exception,SWIG_POINTER_OWN), \ 
      #Exception, SWIGTYPE_p_##Namespace##__##Exception); \ 
     SWIG_fail; \ 
    } \ 
/**/ 

// should be in "derived first" order 
#define FOR_EACH_EXCEPTION(ACTION) \ 
    ACTION(API,UnreachableException) \ 
    ACTION(API,TimeoutException) \ 
    ACTION(API,InvalidAddressException) \ 
    ACTION(API,NetworkException) \ 
    ACTION(API,Exception) \ 
/**/ 
// In order to remove macros, need traits: 
// http://swig.10945.n7.nabble.com/traits-based-access-to-swig-type-info-td12315.html 
%} 

%exception { 
    try { 
     $action 
    } 
    FOR_EACH_EXCEPTION(CATCH_PE) 
    catch (const std::exception & e) 
    { 
     SWIG_exception(SWIG_RuntimeError, (std::string("C++ std::exception: ") + e.what()).c_str()); 
    } 
    catch (...) 
    { 
     SWIG_exception(SWIG_UnknownError, "C++ anonymous exception"); 
    } 
} 

%include "example.cpp" 

example.cpp:

#include <exception> 
#include <stdexcept> 

namespace API 
{ 
    struct Exception: std::exception 
    { 
     virtual const char* what() const throw() 
     { 
      return "It is API::Exception"; 
     } 
    }; 
    struct NetworkException: Exception 
    { 
     virtual const char* what() const throw() 
     { 
      return "It is API::NetworkException"; 
     } 
    }; 
    struct TimeoutException: NetworkException 
    { 
     virtual const char* what() const throw() 
     { 
      return "It is API::TimeoutException"; 
     } 
    }; 
    struct UnreachableException: NetworkException 
    { 
     virtual const char* what() const throw() 
     { 
      return "It is API::UnreachableException"; 
     } 
    }; 
    struct InvalidAddressException: Exception 
    { 
     virtual const char* what() const throw() 
     { 
      return "It is API::InvalidAddressException"; 
     } 
    }; 

    inline void select(int i) 
    { 
     switch(i) 
     { 
      case 0: throw Exception(); 
      case 1: throw NetworkException(); 
      case 2: throw TimeoutException(); 
      case 3: throw UnreachableException(); 
      case 4: throw InvalidAddressException(); 
      default: throw std::runtime_error("It is std::runtime_error"); 
     } 
    } 
} 

बिल्ड:

swig -c++ -python example.i && 
g++ -fPIC -shared -lpython2.7 example.cpp example_wrap.cxx -I/usr/include/python2.7 -o _example.so 

test.py:

#!/usr/bin/env python2.7 

from exceptions import BaseException 
from example import * 

def catch(i): 
    try: 
     select(i) 
    except UnreachableException as e: 
     print "Caught UnreachableException" 
     print e.what() 
     print e 
    except TimeoutException as e: 
     print "Caught TimeoutException" 
     print e.what() 
     print e 
    except InvalidAddressException as e: 
     print "Caught InvalidAddressException" 
     print e.what() 
     print e 
    except NetworkException as e: 
     print "Caught NetworkException" 
     print e.what() 
     print e 
    except Exception as e: 
     print "Caught Exception" 
     print e.what() 
     print e 
    except BaseException as e: 
     print "Caught BaseException" 
     print str(e) 
    print "_"*16 

for i in xrange(6): 
    catch(i) 

आउटपुट है:

Caught Exception 
It is API::Exception 
<example.Exception; proxy of <Swig Object of type 'API::Exception *' at 0x7f9f54a02120> > 
________________ 
Caught NetworkException 
It is API::NetworkException 
<example.NetworkException; proxy of <Swig Object of type 'API::NetworkException *' at 0x7f9f54a02120> > 
________________ 
Caught TimeoutException 
It is API::TimeoutException 
<example.TimeoutException; proxy of <Swig Object of type 'API::TimeoutException *' at 0x7f9f54a02120> > 
________________ 
Caught UnreachableException 
It is API::UnreachableException 
<example.UnreachableException; proxy of <Swig Object of type 'API::UnreachableException *' at 0x7f9f54a02120> > 
________________ 
Caught InvalidAddressException 
It is API::InvalidAddressException 
<example.InvalidAddressException; proxy of <Swig Object of type 'API::InvalidAddressException *' at 0x7f9f54a02120> > 
________________ 
Caught BaseException 
C++ std::exception: It is std::runtime_error 
________________ 

answer in maillist के आधार पर।