在Python中提前销毁的SWIG carrays/类

2024-10-08 22:24:03 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试使用一种我认为在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的每个循环结束时,都会调用NodeRow的析构函数。所以,即使我做了c_node_arr[n] = node,这个赋值也不会使Python保留node,而是删除它

我假设这是因为SWIG数组与指针一起工作,如果我做^ {< CD4>},它只将指针设置为{{CD5>},然后将在循环的结尾由Python释放(并且将调用C++析构函数),并且^ {}将被挂起指针,指向已经释放的内存位置。p>

有什么解决办法吗?我的方法是不是很糟糕,我应该重新思考(怎么做?)

@Edit:

目前,我看到的唯一解决办法是:

1)将RowArrayNodeArray的所有实例也保存在Python列表中,并在完成后释放它们

2)将赋值从=更改为RowArray,将NodeArray更改为__setitem(idx, value)


Tags: nodedataexampleelementarraynrclassrows
1条回答
网友
1楼 · 发布于 2024-10-08 22:24:03
我想,发生的事情是,Switg触发了许多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发生的事情

所以你实际上有:

  1. [Python]c_node_arr.__setitem__(n, node):将node传递到SWIG
  2. [SWIG]提取底层Node*
  3. [SWIG]呼叫name::setitem(..., *node)
  4. [C++]作为参数传递的一部分,构造一个新的Node对象作为参数的副本(就像Node new_node = node;)。尝试为元素编写一个复制构造函数,我想您会在这里看到一个调用
  5. [C++]将其存储在struct name的某个内部数组中。我猜这第二本书不知怎么被删掉了
  6. 。。。后来[Python]决定删除原始的node对象。这就是您看到析构函数运行的地方。在内部,NodeArray指向(并拥有)原始节点的副本

如果ElementRow可以被复制(使用默认或自定义复制构造函数),那么一切都很好

相关问题 更多 >

    热门问题