英文:
Using pointer to C++ vectors in Cython
问题
我正在尝试在Cython中定义指向C++向量的指针,并且我注意到了一个我无法用我的Cython知识解释的奇怪行为。下面,我创建了一个指向基于T范围的double向量的指针。我要么将a赋给a_low,要么赋给a_high。
from libcpp.vector cimport vector
cdef vector[double] a_low = [1.0, 2e-03, -4e-07, 6.3e-10, -2.21e-5, -3.45e+01];
cdef vector[double] a_high = [-2.21e-01, 4.1e-03, -6.12e-02, 1.65e-09, -9.3e-6, -1.4e+02];
def h_calc(double T):
cdef vector[double] *a
cdef double h
if (T < 1000.0):
a = &a_low;
else:
a = &a_high;
print(a[0])
h = 0.0;
return h;
执行h_calc(1200);输出[-0.221, 0.0041, -0.0612, 1.65e-09, -9.3e-06, -140.0],这是由于print(a[0])导致的。在这里,因为T > 1000,我们看到输出显示了a_high。
我不理解的是为什么a[0]没有返回a_high向量的第一个值,而是整个向量?
英文:
I was trying define pointers to C++ vectors in Cython, and I noticed a strange behavior that I cannot explain with my Cython knowledge. Below, I have created a pointer to a vector of double based on T range. I either assign a to a_low or a_high.
from libcpp.vector cimport vector
cdef vector[double] a_low = [1.0, 2e-03, -4e-07, 6.3e-10, -2.21e-5, -3.45e+01];
cdef vector[double] a_high = [-2.21e-01, 4.1e-03, -6.12e-02, 1.65e-09, -9.3e-6, -1.4e+02];
def h_calc(double T):
cdef vector[double] *a
cdef double h
if (T<1000.0):
a = &a_low;
else:
a = &a_high;
print(a[0])
h = 0.0;
return h;
executing h_calc(1200); gives out [-0.221, 0.0041, -0.0612, 1.65e-09, -9.3e-06, -140.0] which results from print(a[0]). Here, because T>1000, we see a_high was displayed as output.
What I don't understand is why a[0] does not return the first value of the vector a_high , but rather the whole vector?
答案1
得分: 2
在Cython中,解引用(即在C++中的*a)写作a[0],因为前者不是有效的Python语法,而后者是有效的。请参考这里的"Types"部分。
也就是说,发生的情况是:
- 您的
a是类型为vector[double] *的指针, a[0]是解引用版本(即仅为vector[double]类型),print(a[0])将vector[double]转换为Python列表并打印(即整个列表),- (这也是为什么
a[1]会崩溃 - 实际上它在做*(a+1),并且导致内存违规)。
此外,值得一提的是,从Python列表赋值应该可以工作 - Cython会为您有效地将其重写为循环遍历Python列表,并在每个项上调用push_back(...)。
英文:
In Cython dereferencing (i.e. *a in c++) is spelled as a[0] as the former is not valid python syntax while the latter is - see the "Types" section here
I.e. whats happening is:
- your
ais of typevector[double] *, a[0]is the dereferenced version (i.e. just avector[double])print(a[0])convertsvector[double]to a python list and prints that (i.e. the whole list)- (this is also why
a[1]crashes - it's effectively doing*(a+1), and getting a memory violation)
Also for what it's worth the assignment from the python list should work - Cython effectively rewrites it to loop over the python list calling push_back(...) on each item for you.
答案2
得分: 1
[] 是一个 PyObject。你不能将其分配给一个 C++ 类型(如 cdef 中所示)的 vector。转换不是隐式的。可能整个值字符串被视为第一个元素。当访问 a[1] 时会发生什么?
你必须声明这个 vector,并单独分配值给它。
cdef vector[double] a_low
a_low.push_back(1.0)
a_low.push_back(2e-03)
...
也许你还可以尝试使用 vector::insert (iterator position, const value_type& val);,它可以接受一个元素数组。同样,你必须传递一个 C 数组类型,所以你必须在传递之前声明并填充你的数组。
cdef double array[6]
array[:] = [1.0, 2e-03, -4e-07, 6.3e-10, -2.21e-5, -3.45e+01]
然后将其传递给 vector::insert。
正如你所看到的,你可以用一行代码填充一个 C 风格的数组,但不能填充一个 Cython 中的 vector。这引发了一个问题,为什么不直接在开始时使用数组呢?
英文:
[] is a PyObject. You can't assign it to a c++ type (as evidenced with cdef) of a vector. The conversion isn't implicit. Likely the whole string of values is being treated as the first element. What happens when you access a[1]?
You have to declare the vector, and assign the values to it separately.
cdef vector[double] a_low
a_low.push_back(1.0)
a_low.push_back(2e-03)
...
Perhaps you can also try experimenting with
vector::insert (iterator position, const value_type& val);, which can take an array of elements. Again, you would have to pass it a c array type, so you would have to declare and fill your array before passing it.
cdef double array[6]
array[:] = [1.0, 2e-03, -4e-07, 6.3e-10, -2.21e-5, -3.45e+01] then pass it to vector::insert.
As you can see you can fill a C style array but not a vector in Cython in a one-liner. This raises the question, why not just use arrays in the first place?
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论