SWIG carray/class 在 Python 中过早地被销毁
SWIG carrays/classes prematurely destroyed in 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 中的每个循环结束时,都会调用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)
我认为正在发生的事情是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
发生的事情.
所以你实际上有:
- [Python]
c_node_arr.__setitem__(n, node)
: 将node
传递到 SWIG。 - [SWIG] 提取底层
Node*
。 - [SWIG] 呼叫
name::setitem(..., *node)
。 - [C++] 作为参数传递的一部分,构造一个新的
Node
对象作为参数的副本(好像Node new_node = node;
(。尝试为 Element 编写一个复制构造函数,我想你会在这里看到一个调用。 - [C++] 将其存储在某个内部
struct name
数组中。我想这第二个副本以某种方式被省略了。 - 。后。。。[蟒蛇]决定删除原始
node
对象。这是您看到析构函数正在运行的地方。在内部,NodeArray
指向(并拥有(原始节点的副本。
如果Element
,Row
可以复制(使用默认或自定义复制构造函数(,那么一切都很好。
- 这个语法std::class<>{}(arg1, arg2) 在C++中是什么意思?
- C++核心准则 C35 对于接口类"A base class destructor should be either public and virtual, or protected and nonv
- 使用模板进行堆栈实现; "name followed by :: must be a class or namespace"
- "Undefined class"作为is_base_of的论据
- 如何将class.cpp和class.hpp编译为一个.o文件
- '{'标记之前的预期类名,然后在预声明时无效使用不完整的类型'class class_name'
- 如何使用"derived input class"创建派生类?
- 错误:"Left of getValue must have class/struct/union"
- ' class a : b ' 和 ' class a : public b ' 之间的继承类不同
- Pybind11 Class Definition
- 在C++中使用没有合作伙伴Class/Cpp文件的头文件是否实用
- C2011 'CMemDC':Visual Studio 2019中的'class'类型重新定义
- TypeError: [c++ addon class] 不是构造函数
- C++ class template
- 当初始值设定项是基类名时'initializer does not name a non-static data member or base class'错误
- Clearing Class Foo with new(pFoo) Foo()
- C++ class vs a library
- 继承类时"invalid use of incomplete type ‘class tree_node_t’"
- SWIG carray/class 在 Python 中过早地被销毁
- 将数据添加到 CArray 会产生错误"cannot access private member declared in class 'CObject'"