Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/159.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 动态重定向自定义C++;使用SWIG将异常作为Python异常_C++_Python_Exception_Reflection_Swig - Fatal编程技术网

C++ 动态重定向自定义C++;使用SWIG将异常作为Python异常

C++ 动态重定向自定义C++;使用SWIG将异常作为Python异常,c++,python,exception,reflection,swig,C++,Python,Exception,Reflection,Swig,形势 我想用SWIG为C++ API创建Python语言绑定。某些API函数可能引发异常。C++应用程序具有自定义异常的层次结构,例如这个例子: std::exception -> API::Exception -> API::NetworkException -> API::TimeoutException -> API::UnreachableException -> API::InvalidAddressExcept

形势

<>我想用SWIG为C++ API创建Python语言绑定。某些API函数可能引发异常。C++应用程序具有自定义异常的层次结构,例如这个例子:

std::exception
  -> API::Exception
    -> API::NetworkException
      -> API::TimeoutException
      -> API::UnreachableException
    -> API::InvalidAddressException
所需的行为如下所示:

// 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;
}
}
  • 所有异常类型都应该有一个匹配的Python类作为包装器。这些包装类应该是有效的Python异常

  • 当一个API调用抛出一个C++异常时,它应该被捕获。<强>相应的Python异常(即捕获的C++异常的包装类)应该是<强>抛出>

  • >P>这应该是一个动态过程:Python <强>异常类型在运行时,仅基于捕获的C++异常的运行时类型。这样,就不需要在SWIG接口文件中描述完整的异常层次结构

    问题和问题

  • 包装器类不是Python例外

    虽然SWIG为所有自定义异常(与任何其他类一样)创建包装类,但这些类不是Python异常。基本异常(
    API::exception
    在本例中)的包装器扩展了
    Object
    ,而不是
    BaseException
    ,Python中的所有异常都应该派生自该Python类

    此外,似乎不可能让SWIG手动添加父类。注意:当通过使用
    %typemap(javabase)
    将SWIG与Java结合使用时,这是可能的(有关详细信息,请参阅)

  • 服务器如何抛出用户定义的异常

    从Python C API引发Python异常的最常见方法是调用
    PyErr\u SetString
    。这也显示在下面的演示应用程序中

    但对于Python的标准(内置)异常来说,这只是一个小问题,因为对它们的引用存储在Python C API的全局变量[]中

    我知道有一种方法
    PyErr\u NewException
    可以获取对自定义异常的引用,但我没有做到这一点

  • > P>如何在运行时评估C++类型,然后根据名称查找相应的Python包装类?< /P> 我假设一个Python类可以在运行时通过Python C API的名称进行搜索。这是路吗?在实践中又是如何做到的呢

    演示应用程序

    为了解决这个问题,我创建了一个简单的C++ API,它具有一个函数,它计算一个数的阶乘。它有一个最小的自定义异常层次结构,只包含一个类

    TooBigException

    注意:此异常作为一般问题中的基本异常,应用程序应使用它的任何子类。这意味着解决方案只能使用捕获的异常的动态(即运行时)类型在Python中重新显示它(见下文)

    演示应用程序的完整源代码如下:

    // 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;
    }
    }
    
    当前实施情况

    我当前的实现仍然(成功)抛出了一个固定的标准Python异常。然后将上面的代码
    替换为:

    PyErr_SetString(PyExc_Exception, (std::string("C++ self-defined exception ") + e.what()).c_str());
    return NULL;
    
    这在Python中提供了以下(预期)行为:

    >>> import numbers
    >>> fact(11)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    Exception: C++ self-defined exception Value too big
    
    >>导入编号
    >>>事实(11)
    回溯(最近一次呼叫最后一次):
    文件“”,第1行,在
    异常:C++自定义异常值太大
    
    似乎有人在swig用户列表上回答了您的基本问题

    %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;
      } 
    }
    
    %异常{
    试一试{
    $action
    }捕获(MyException&_e){
    SWIG_Python_Raise(SWIG_NewPointerObj(
    (新的MyException(静态投射),
    SWIGTYPE_p_MyException,SWIG_POINTER_OWN),
    “MyException”,SWIGTYPE_p_MyException);
    SWIG_失败;
    } 
    }
    

    我相信,这确实假设您已经为您的异常类生成了包装器

    您的层次结构示例

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

    %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"
    
    示例.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");
            }
        }
    }
    
    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
    ________________
    
    捕获异常
    它是API::Exception
    ________________
    捕获的网络异常
    它是API::NetworkException
    ________________
    捕获的超时异常
    它是API::TimeoutException
    ________________
    捕获无法访问的异常
    它是API::UnreachableException
    ________________
    捕获无效地址异常
    它是API::InvalidAddressException
    ________________
    捕获的基本异常
    C++ STD::异常:它是STD::运行时错误
    ________________
    

    基于。

    我不太确定您想要什么,但您是否查看过该代码在第二种情况下是否有帮助<代码>抛出这确实是答案的一部分。但是,正如问题中明确指出的,我希望使用动态类型,而此解决方案执行静态转换。换句话说:MyException的任何子类都将被捕获并更改为MyException,所有子类信息都将丢失。
    #!/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
    ________________