3

私の問題は次のとおりです。C++コードを思い通りに変更できません(私が書いたものではなく、知的財産の制約の下にあります)。Python メインを介して Python コードとリンクする必要があります。リフレクションにはboost::pythonを使用します。コードのある時点で、C++ 関数は C++ 関数の Python オーバーロード関数を使用してパラメーターを変更します。この関数は、Python 内で使用するとうまく機能します。ただし、C++ 関数によって呼び出された場合、パラメーターの変更は、C++ に戻っている間は考慮されません。問題をモデル化するために、問題を切り分けることを目的とした単純化されたバージョンを作成しました。

C++ クラスは次のとおりです。

#include <iostream>
using namespace std;
#include <boost/ref.hpp>

//Class aimed at modeling a C++ user's type that should be used in Python
class C
{
public:
    double myC;
    C(){}
    ~C(){}

    void setValue(double val) {
        myC = val;
    }

    double getValue() {
        return myC;
    }
};

/*
    This class will be derived in Python
    We want to be sure that:
    - void (g) and non void (f) functions are properly reflected and extended in Python
    - a function (h) with a local type (C) will properly use the python overloaded     function of a C++ function (g)
*/

class A
{
public:
    A(){int A_x=0;}
    virtual ~A(){}
    virtual int f(int Ivar){
        Ivar = 0;
        return Ivar;
    }
    virtual void g(C * myC){
        C calledC;
        cout << "I should not be here" << endl;   //When B::setparam call g, it should be the Python g, not the virtual function from base class
        calledC.setValue(0.);
        //return *myC;
    }
    C h(){                  //This function wont be overloaded in Python
        C myC;
        //myC.setValue(0.);
        this->g(&myC);      //We want myC to be modified, and the python overloaded version of g to be used
        cout << "Value back in C++: " << myC.getValue() << endl; //We want to verify if myC has been modified back in C++
        return myC;
    }
};

/*
    This class will be called from a main in Python.
    It's function setparam is aimed at ensuring that Python extension of a C++ class is supported properly
*/

class B
{
public:
    B(A & a){
        setparam(a); 
    }
    B(){
        int u;
        u = 0;
    }
    virtual ~B(){}
    void setparam(A & a){
        a.h();              //Here the code should call the h overloaded function of the derived class of A in Python
    }
};

boost::python ラッパー:

#include <boost/python.hpp>
#include <Python.h>
#include <object.h>
#include "ClassA.h"

#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
#include <boost/python/implicit.hpp>
#include <iostream>
using namespace std;

using namespace boost::python;

/*
    A wrapper is used to allow overload of virtual A function
*/
struct WrapperClassA : A, boost::python::wrapper<A>{
    int f(int Ivar){
        if(override f = this->get_override("f")){
            return f(Ivar);
        }
        else {
            return A::f(Ivar);
        }
    }
    int default_f(int Ivar){
        return this->A::f(Ivar);
    }

    void g(C * myC){
        if(override g = this->get_override("g")){
                    g(myC);
        }
        else {
            A::g(myC);
        }
    }
    void default_g(C * myC){
        this->A::g(myC);
    }
};

/*
    Refection of necessary classes and functions for Python
*/
BOOST_PYTHON_MODULE(myWrapper){
    class_<WrapperClassA, boost::noncopyable>("A", init<>())
    .def("f", &A::f, &WrapperClassA::default_f)
    .def("g", &A::g, &WrapperClassA::default_g)
    ;

    class_<B, boost::noncopyable>("B", init<>())
    .def("setparam", &B::setparam)
    ;

    class_<C>("C", init<>())
    .def("setValue", &C::setValue)
    .def("getValue", &C::getValue)
    .def_readwrite("myC", &C::myC)
    ;
}

Python コード:

from math import *
# C++ library
from myWrapper import *

"""
    Extension of C++ class A
    APy should be used when A type argument is called
    g should be able to use a C++ C type object and to modify it
    The constructor call g in order to verify that myC is treated as mutable within Python
"""
class APy(A):
    def __init__(self):
        A.__init__(self)
        n = 0
        x = 0.
        myC = C()
        self.g(myC)
        print("value after a 1st call within Python: " + repr(myC.getValue()))

    def f(self, n):
        n = 5
        return n

    def g(self, myC):
        x = 7.0
        myC.setValue(x)
        print("value in Python: " + repr(myC.getValue()))

"""
    Main
    myB.setparam should be able to pass a APy argument
"""
myA = APy()
myB = B()
myB.setparam(myA)

コードを実行すると、 print("value in Python: " + repr(myC.getValue())) print 7 ですが、 cout << myC.getValue() << endl print 0 で、変数を7. 助けてくれてありがとう。

4

1 に答える 1

1

ここでの問題はC、呼び出しでインスタンスを Python に変換するときに、ポインタを渡したにもかかわらずg(myC)、Boost.Python が浅いコンバータではなく値によるコンバータを使用する (つまり、インスタンスをコピーする) ことです。C

これは仕様によるものです。C++ ポインターを Python に渡すと、Boost.Python は、Python レイヤーがまだアクセスしている間、Python コードが他の C++ コードがそれを削除することを心配する必要がないことを保証したいと考えています。危険なメモリエラーを引き起こします。それを確実にする唯一の方法は、オブジェクトをコピーすることです。

myCBoost.Python に強制的にオブジェクトを参照渡しさせたい場合はg(boost::python::ptr(myC))(またはg(boost::ref(*myC))null でないことがわかっている場合) を使用しますが、これは危険であることに注意してください。g()の Python 実装が、その有効期間を超えてその引数を保持しようとしないことを確認する必要があります。

詳細については、次を参照してください。

http://www.boost.org/doc/libs/1_48_0/libs/python/doc/v2/callbacks.html

boost::shared_ptr安全な方法でコピーせずに Python に引数を渡すために使用することもできます。

boost python: C++ 仮想関数を呼び出す方法

于 2012-06-09T14:54:02.530 に答える