英文:
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
a
is 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?
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论