我试图使用一种相当常见的结构,我认为在C / C ++中,有些东西是这样的:
// data.hpp
class Element {
public:
int value;
~Element() { std::cout << "In node destructor" << std::endl; }
};
class Row {
public:
Row(Element *elements) {/*initialize elements, assign ptrs*/};
std::vector<Element *> elements;
};
class Dataset {
public:
Dataset(Row *rows) {/*initialize rows, assign ptrs*/};
std::vector<Row *> rows;
};
存储指针,因为它实际上在CPU和GPU(CUDA)上使用,我只想存储指针,以便每个设备可以自己计算出对象的实际位置。
我的SWIG映射非常基础:
/* File : data.i */
%{
#include "data.hpp"
%}
%include carrays.i
%include "data.hpp"
%array_class(Node, NodeArray)
%array_class(Row, RowArray)
现在我需要将Python / Numpy数组转换为行数组,以便将它们传递给Dataset
构造函数。想到这样的事情可能有用:
def array_to_rows(X):
nr_rows = np.shape(X)[0]
c_row_arr = example.RowArray(nr_nodes)
for r in range(nr_rows):
nr_nodes = len(X[r])
c_node_arr = example.NodeArray(nr_nodes)
for n in range(nr_nodes):
node = example.Node()
node.value = int(X[r][n])
c_node_arr[n] = node // <-- after this line node's destructor is called
c_row_arr[r] = example.Row(node_arr) // <-- after this line row's destructor is called and destructor for each Node in c_node_arr
return c_row_arr
示例电话:
import example as example
X = [
[1],
[2,3],
[4,5,6]
]
rows = array_to_rows(X)
问题是,在Python的每个循环结束时,调用Node
和Row
的析构函数。所以,即使我c_node_arr[n] = node
,这项任务也不会让Python继续node
,但会将其删除......
我假设这是因为SWIG数组正在使用指针,如果我执行c_node_arr[n] = node
,它只会将指针设置为node
,然后Python将在最后发布循环(和C ++析构函数将被调用),c_node_arr
将悬挂一个指向已经释放的内存位置的指针。
有没有解决方法?我的方法是不是很糟糕,我应该重新思考它(如何?)。
@Edit:
目前我看到的唯一解决方法是:
1)将所有RowArray
和NodeArray
的实例都保存在Python列表中,并在我完成后释放它们
2)将作业更改为RowArray
和NodeArray
从=
更改为__setitem(idx, value)
答案 0 :(得分:0)
我认为正在发生的事情是SWIG正在触发您的C ++对象的许多副本。我认为它不会留下任何悬空的指针。
在http://www.swig.org/Doc1.3/Library.html中,%array_class(type,name)
是:
struct name {
...
void setitem(int index, type value); // Set item
}
我认为这就是在c_node_arr[n] = node
发生的事情。
所以您实际上有:
c_node_arr.__setitem__(n, node)
:将node
传递到SWIG。Node*
。name::setitem(..., *node)
。Node
对象作为参数的副本(就像Node new_node = node;
一样)。尝试为Element编写一个复制构造函数,我想您会在这里看到一个调用。struct name
的某个内部数组中。我想这第二份副本已被删除了。node
对象。这是您看到析构函数运行的地方。在内部,NodeArray
指向(并拥有)原始节点的副本。如果可以将Element
,Row
设为可复制(使用默认或自定义副本构造函数),则一切正常。