这是最奇怪的错误,我试图从c ++函数中获取一个numpy数组,将引用返回给一个向量,整个包裹使用Cython。
我可以让它返回vector<int>
而不是vector<int>&
,但我想了解使用引用时发生了什么。这是一种重现错误的方法:
#ifndef MYCLASS_H
#define MYCLASS_H
#include <vector>
#include <string>
namespace vec {
class IntVector {
private:
std::vector<int> vec;
public:
IntVector();
virtual ~IntVector();
std::vector<int>& get_vec(); #return a reference !
};
}
#endif
#include "cmyclass.h"
#include <iostream>
using namespace vec;
IntVector::IntVector(){
for(int i=10; i<20; ++i){
vec.push_back(i);
}
}
IntVector::~IntVector(){
}
std::vector<int>& IntVector::get_vec(){
std::vector<int> buff;
buff.reserve(vec.size());
for(int i=0; i<vec.size(); ++i){
buff.push_back(vec[i]);
}
return buff;
}
import numpy as np
cimport numpy as np
from libcpp.vector cimport vector
cdef extern from "cmyclass.h" namespace "vec":
cdef cppclass IntVector:
IntVector() except +
vector[int]& get_vec()
cdef class IntVec:
cdef IntVector* _thisptr
def __cinit__(self):
self._thisptr = new IntVector()
def __dealloc__(self):
del self._thisptr
def __init__(self):
pass
def get_vec(self):
cdef vector[int] buff;
buff = self._thisptr.get_vec();
return np.asarray(buff)
from distutils.core import setup
from Cython.Build import cythonize
from distutils.extension import Extension
sourcefiles = ['myclass.pyx', 'cmyclass.cc']
compile_opts = ['-std=c++11']
ext=[Extension('*',
sourcefiles,
extra_compile_args=compile_opts,
language='c++')]
setup(
ext_modules=cythonize(ext)
)
您可以使用python setup.py build_ext --inplace
>>> import myclass
>>> vec = myclass.IntVec()
>>> vec.get_vec()
array([ 0, 0, 12, 13, 14, 15, 16, 17, 18, 19])
您可以看到两个第一个值设置为零(它们应该是10和11)!如果我们返回vector<int>
而不是对vector<int>
的引用,代码将正常工作。
知道为什么会这样吗?
将矢量作为参数传递。
#ifndef MYCLASS_H
#define MYCLASS_H
#include <vector>
#include <string>
namespace vec {
class IntVector {
private:
std::vector<int> vec;
public:
IntVector();
virtual ~IntVector();
void get_vec(std::vector<int>&);
};
}
#endif
#include "cmyclass.h"
#include <iostream>
using namespace vec;
IntVector::IntVector(){
for(int i=10; i<20; ++i){
vec.push_back(i);
}
}
IntVector::~IntVector(){
}
void IntVector::get_vec(std::vector<int>& buff){
buff.reserve(vec.size());
for(int i=0; i<vec.size(); ++i){
buff.push_back(vec[i]);
}
return buff;
}
import numpy as np
cimport numpy as np
from libcpp.vector cimport vector
cdef extern from "cmyclass.h" namespace "vec":
cdef cppclass IntVector:
IntVector() except +
void get_vec(vector[int]&)
cdef class IntVec:
cdef IntVector* _thisptr
def __cinit__(self):
self._thisptr = new IntVector()
def __dealloc__(self):
del self._thisptr
def __init__(self):
pass
def get_vec(self):
cdef vector[int] buff;
self._thisptr.get_vec(buff);
return np.asarray(buff)
from distutils.core import setup
from Cython.Build import cythonize
from distutils.extension import Extension
sourcefiles = ['myclass.pyx', 'cmyclass.cc']
compile_opts = ['-std=c++11']
ext=[Extension('*',
sourcefiles,
extra_compile_args=compile_opts,
language='c++')]
setup(
ext_modules=cythonize(ext)
)
答案 0 :(得分:1)
你的主要目的似乎是让numpy使用在C ++向量中分配的内存。为此,您可能更好地实现User.includes(:car)
.where(car: { bought_at < (user.birthday + 18.years)})
的缓冲协议。 Cython文档提供了一个Matrix class based around a vector的示例,您可以简化它(因为您的情况只有1D)。您真正需要做的就是创建函数IntVec
和__getbuffer__
(后者可以为空白,如示例文档中所示)。 (我不认为复制/粘贴文档有很大的价值)
这样做可以让您__releasebuffer__
直接传递给IntVec
。生成的numpy数组将使用np.asarray
进行存储,并保留对IntVec
的引用,以确保它不会被删除。您也可以在此类中使用Cython内存视图(如果这有用)。