这里的问题是,在python中公开向量的迭代过程中,我每次都会为同一个对象获得不同的地址。
据我所知,python在每次迭代时通过我的boost::shared\u ptr创建pyobject,迭代后(实际上是在第二次迭代之后)垃圾收集器释放该地址,尽管元素是boost::shared\u ptr-s。
当元素在python的列表中时,它们具有在迭代过程中不变的唯一地址。这就是我想要实现的。
我试图通过在stackoverflow中访问不同的boost文档和不同的QA来上网,但没有解决我的问题。
我创建了一个小示例来演示这个问题。
以下是C++代码:
#include <vector>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/python.hpp>
namespace bp = boost::python;
class A {
public:
A() : m_int(0) { }
A(int numb) : m_int(numb) { }
int get_m() const { return m_int; }
private:
int m_int;
};
std::ostream& operator<<(std::ostream& out, const A& obj) {
out << obj.get_m();
return out;
}
using APtr = boost::shared_ptr<A>;
using ACont = std::vector<APtr>;
using AContPtr = boost::shared_ptr<ACont>;
APtr CreateA() {
return boost::make_shared<A>();
}
APtr CreateAFromNumb(int numb) {
return boost::make_shared<A>(numb);
}
AContPtr CreateEmptyACont() {
return boost::make_shared<ACont>();
}
AContPtr CreateFullACont(int size) {
ACont vec{};
for (int i = 0; i < size; ++i) {
vec.push_back(boost::make_shared<A>(i));
}
return boost::make_shared<ACont>(vec);
}
BOOST_PYTHON_MODULE(example) {
bp::class_<A, APtr, boost::noncopyable>("A", bp::no_init)
.def("__init__", bp::make_constructor(CreateA))
.def("__init__", bp::make_constructor(CreateAFromNumb))
.def(bp::self_ns::str(bp::self))
;
bp::register_ptr_to_python<APtr>();
bp::class_<ACont, AContPtr, boost::noncopyable>("ACont", bp::no_init)
.def("__init__", bp::make_constructor(CreateEmptyACont))
.def("__init__", bp::make_constructor(CreateFullACont))
.def("__iter__", bp::iterator<ACont>())
.def("__len__", &ACont::size)
;
bp::register_ptr_to_python<AContPtr>();
}
下面是它在python中的用法:
#!/usr/bin/env python
from example import *
vec = ACont(4)
print len(vec)
print "VEC", vec
for x in vec:
print x,
print repr(x)
print "VEC", vec
for x in vec:
print x,
print repr(x)
l = [x for x in vec]
print "LIST"
for x in l:
print x,
print repr(x)
print "LIST"
for x in l:
print x,
print repr(x)
在暴露的std::vector/boost::shared\u ptr上迭代时<std::矢量>我在两个连续的迭代中得到了相同元素的不同地址。
-
Python在第一次迭代时为第一个项创建pyobject,并
显示其地址。
-
在第二次迭代中,python为另一个地址上的第二个元素创建另一个pyobject。
-
垃圾收集器发现第一个地址不再可用,并将其释放。
-
在第三次迭代中,python在与第一个元素相同的地址中为第三个元素创建另一个pyobject,因为gc刚刚释放了它。
-
等等
但是对相同元素列表的迭代是正确的,因为python不会创建/破坏pyobjects,因为它们在列表本身中有引用。
以下是python运行的输出:
4
VEC <example.ACont object at 0x7ffff7ea9578>
0 <example.A object at 0x7ffff7eb27d0> # address 1
1 <example.A object at 0x7ffff7eb2848> # address 2
2 <example.A object at 0x7ffff7eb27d0> # address 1 since gc just have freed it
3 <example.A object at 0x7ffff7eb2848> # so on
VEC <example.ACont object at 0x7ffff7ea9578>
0 <example.A object at 0x7ffff7eb27d0>
1 <example.A object at 0x7ffff7eb2848>
2 <example.A object at 0x7ffff7eb27d0>
3 <example.A object at 0x7ffff7eb2848>
LIST
0 <example.A object at 0x7ffff7eb27d0> # address 1
1 <example.A object at 0x7ffff7eb2848> # address 2
2 <example.A object at 0x7ffff7eb28c0> # address 3
3 <example.A object at 0x7ffff7eb2938> # address 4
LIST
0 <example.A object at 0x7ffff7eb27d0>
1 <example.A object at 0x7ffff7eb2848>
2 <example.A object at 0x7ffff7eb28c0>
3 <example.A object at 0x7ffff7eb2938>
总之,考虑到这些对象是某些对象的boost::shared\u ptr-s,我想知道是否有一种方法不在python中为C++中创建的每个元素创建pyobjects。
提前谢谢你。
P、 我正在使用boost版本1.60和python 2.7(anaconda包)。