Python Cython:Numpy数组从引用中获取时缺少前两个元素 这是最奇怪的错误,我试图从C++函数中得到一个麻木数组,将引用< /强>返回到向量,整个用Cython包装。< /P>

Python Cython:Numpy数组从引用中获取时缺少前两个元素 这是最奇怪的错误,我试图从C++函数中得到一个麻木数组,将引用< /强>返回到向量,整个用Cython包装。< /P>,python,c++,numpy,cython,Python,C++,Numpy,Cython,我可以让它返回向量而不是向量&,但我想了解使用引用时发生的情况。以下是重现错误的方法: cmyclass.h setup.py 您可以使用python setup.py build\u ext--inplace 用例 您可以看到前两个值被设置为零(它们应该是10和11)!如果我们返回的是向量而不是向量的引用,那么代码就可以正常工作 知道为什么会这样吗 编辑:最终解决方案 将向量作为参数传递 cmyclass.h setup.py 你的主要目标是让NUBPY使用内存分配给C++向量。为此,您最好为

我可以让它返回
向量
而不是
向量&
,但我想了解使用引用时发生的情况。以下是重现错误的方法:

cmyclass.h setup.py 您可以使用
python setup.py build\u ext--inplace

用例 您可以看到前两个值被设置为零(它们应该是10和11)!如果我们返回的是
向量
而不是
向量
的引用,那么代码就可以正常工作

知道为什么会这样吗

编辑:最终解决方案 将向量作为参数传递

cmyclass.h setup.py
<>你的主要目标是让NUBPY使用内存分配给C++向量。为此,您最好为
IntVec
实现缓冲区协议。Cython文档给出了一个可以简化的示例(因为您的案例只有1D)。您真正需要做的就是创建函数
\uuu getbuffer\uuuuuuuu
\uuuuuuu releasebuffer\uuuuuuuuu
(后者可以为空,如示例文档中所示)。(我认为在这里复制/粘贴文档没有太大价值)


这样做将允许您将
IntVec
直接传递到
np.asarray
。生成的numpy数组将使用
IntVec
进行存储,并保留对
IntVec
的引用,以确保它不会被删除。你也可以使用Cython记忆视图与这个类(如果这是有用的)。< /P>你的C++代码返回一个对本地变量的引用,这是一个相当大的灾难。编译器可能会对此发出警告…您的函数应该是
const std::vector&get_vec()const{return vec;}
std::vector&get_vec(){return vec;}
std::vector get_vec(){return vec;}
,这取决于您想要实现的功能,但不返回对临时对象的引用,正如戴维德指出的,你是对的!我通过在
.pyx
文件中声明向量并将引用作为参数传递,解决了这个问题。还有一个问题:
np.asarray
是否在数组中创建数据副本?理想情况下,我希望避免复制数据。
np.asarray
仅在需要时进行复制。你可以很容易地自己检查——写出相关的内存地址,看看它们是否匹配。它肯定会复制,可能会复制两次(先复制到Python列表,然后复制到数组)
#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)
)
>>> import myclass
>>> vec = myclass.IntVec()
>>> vec.get_vec()
array([ 0,  0, 12, 13, 14, 15, 16, 17, 18, 19])
#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)
)