Я пытаюсь работать с довольно распространенной структурой, я думаю, в 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)