8

std::vector を返す C++ 関数があり、それを Python で使用したいので、C numpy API を使用しています。

static PyObject *
py_integrate(PyObject *self, PyObject *args){
    ...
    std::vector<double> integral;
    cpp_function(integral);  // This changes integral
    npy_intp size = {integral.size()};
    PyObject *out = PyArray_SimpleNewFromData(1, &size, NPY_DOUBLE, &(integral[0]));
    return out;
}

Pythonから呼び出す方法は次のとおりです。

import matplotlib.pyplot as plt

a = py_integrate(parameters)
print a
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(a)
print a

何が起こるか: 最初の印刷は問題なく、値は正しいです。しかし、私がプロットaすると、そうではありません。1E-308 1E-308 ...2 番目のプリントでは、または0 0 0 ...初期化されていないメモリのような非常に奇妙な値が表示されます。最初の印刷がOKな理由がわかりません。

部分的な解決策 (機能しない):

static void DeleteVector(void *ptr)
{
    std::cout << "Delete" << std::endl;
    vector * v = static_cast<std::vector<double> * >(ptr);
    delete v;
    return;
}

static PyObject *
cppfunction(PyObject *self, PyObject *args)
{
    std::vector<double> *vector = new std::vector<double>();
    vector->push_back(1.);
    PyObject *py_integral = PyCObject_FromVoidPtr(vector, DeleteVector);
    npy_intp size = {vector->size()};
    PyArrayObject *out;
    ((PyArrayObject*) out)->base = py_integral;
    return (PyObject*)(out);
}
4

2 に答える 2

11

あなたのstd::vectorオブジェクトはその関数に対してローカルであるように見えます。PyArray_SimpleNewFromData渡したデータのコピーは作成しません。ポインタを保持するだけです。したがって、py_integrate 関数が戻ると、ベクトルの割り当てが解除されます。解放されたメモリにはまだ何も書き込まれていないため、印刷は初めて機能しますが、次の印刷に到達するまでに、別の何かがそのメモリを使用しているため、値が異なります。

独自のストレージ スペースを所有する NumPy 配列を作成し、そこにデータをコピーする必要があります。

または、ベクターをヒープに割り当てます。次に、それへのポインターをCObjectに格納します。ベクターを削除するデストラクタを提供します。次に、C レベルのPyArrayObject型を見てみましょう。というPyObject *メンバーがいbaseます。そこに保管してくださいCObject。次に、NumPy 配列がガベージ コレクションされると、この基本オブジェクトの参照カウントが減分され、他の場所でコピーを取得していないと仮定すると、指定したデストラクタのおかげでベクトルが削除されます。

フィクサーアッパー

実際に PyArray を作成するのを忘れていました。これを試して:

(あなたは投稿していないDeleteVectorので、それが正しいことを祈るしかありません)

std::vector<double> *vector = new std::vector<double>();
vector->push_back(1.);
PyObject *py_integral = PyCObject_FromVoidPtr(vector, DeleteVector);
npy_intp size = {vector->size()};
PyObject *out = PyArray_SimpleNewFromData(1, &size, NPY_DOUBLE, &((*vector)[0]));
((PyArrayObject*) out)->base = py_integral;
return out;

注: 私は C++ プログラマーではないので&((*vector)[0])、ベクトルへのポインターで意図したとおりに機能するとしか思えません。ベクトルを大きくすると、そのストレージ領域が再割り当てされることは知っているので、そのポインタを取得した後にサイズを大きくしないでください。そうしないと、有効ではなくなります。

于 2010-05-27T21:18:50.483 に答える