我使用Cython在Python / C ++代码之间存在内存所有权问题。我不确定解决这个问题的最佳方法是什么。所以我感谢任何帮助。
我的策略如下:
对于NetInfo对象,我需要存储指向其他NetInfo对象的指针,以指示两个对象之间的交互。
我的(相关)C ++代码如下:
struct NetInfoData;
class NetInfo {
public:
NetInfo();
NetInfo(NetInfo const& rhs);
virtual ~NetInfo();
...
std::vector<NetInfo*> getBridgedNets() const;
void addBridgedNet(NetInfo const* ni);
protected:
NetInfoData* data_;
};
struct NetInfoData
{
std::string name;
...
std::vector<NetInfo*> bridged_nets; <-- NOTE: Storing pointers.
};
NetInfo::NetInfo()
: data_(0)
{
std::cout << "Constructor " << this << std::endl;
data_ = new NetInfoData();
}
NetInfo::~NetInfo()
{
std::cout << "Destructor " << this << std::endl;
delete data_;
}
NetInfo::NetInfo(NetInfo const& rhs)
: data_(0)
{
std::cout << "Copy constructor " << this << std::endl;
data_ = new NetInfoData();
data_->name = rhs.data_->name;
...
data_->bridged_nets = rhs.data_->bridged_nets;
}
std::vector<NetInfo*>
NetInfo::getBridgedNets() const
{
return data_->bridged_nets;
}
void
NetInfo::addBridgedNet(NetInfo* n)
{
data_->bridged_nets.push_back(n);
}
我的(相关)Cython代码如下。它编译/工作正常。
from cython.operator cimport dereference as deref
from libcpp.vector cimport vector
cdef extern from 'NetInfo.h':
cdef cppclass NetInfo:
NetInfo() except +
NetInfo(NetInfo&) except +
...
vector[NetInfo*] getBridgedNets()
void addBridgedNet(NetInfo*)
cdef class PyNetInfo:
cdef NetInfo* thisptr
def __cinit__(self, PyNetInfo ni=None):
if ni is not None:
self.thisptr = new NetInfo(deref(ni.thisptr))
else:
self.thisptr = new NetInfo()
def __dealloc__(self):
del self.thisptr
...
def get_bridged_nets(self):
cdef PyNetInfo r
cdef NetInfo* n
cdef vector[NetInfo*] nets = self.thisptr.getBridgedNets()
result = []
for n in nets:
r = PyNetInfo.__new__(PyNetInfo)
r.thisptr = n
result.append(r)
return result
def add_bridged_net(self, PyNetInfo ni):
self.thisptr.addBridgedNet(ni.thisptr)
现在我的Python伪代码如下:
import PyNetInfo as NetInfo
a = NetInfo() # Create a
Update data members of a # Populate a
tmp = NetInfo(a) # Call copy constructor of a
for n in xrange(5): # a interacts with five other NetInfo objects so create and call them to a via add_bridged_net()
x = NetInfo(tmp) # Call copy constructor to make copy of tmp (not a!!)
Update data members of x
a.add_bridged_net(x) # Store pointer to x in a (a is updated!)
违规的代码是 x = NetInfo(tmp)。在第二次迭代中,分配给x的旧内存将被释放,因为x现在指向一个新对象。这将导致a现在包含无效指针。
示例运行:
create a
Constructor 0x101ecd0
create tmp
Copy constructor 0xd71d30
create bridge x
Copy constructor 0xd71bb0
add bridged net:
create bridge x
Copy constructor 0xc9f740
Destructor 0xd71bb0 <--- Destructor on old x is called due to reassignment which causes a to contain an invalid pointer (hence, eventually segfault)
add bridged net:
我不完全确定如何管理内存来解决这个问题。有人可以帮忙吗?
我在考虑使用共享指针?所以在我的C ++代码中,我说
typedef std::shared_ptr<NetInfo> NetInfoShPtr;
然后,
std::vector<NetInfo*> bridged_nets -> std::vector<NetInfoShPtr> bridged_nets;
但是后来我不确定在cython方面做些什么。这会有用还是还有其他(更容易?)的方式?谢谢你的任何想法。
答案 0 :(得分:2)
我能够使用共享指针来解决这个问题(让它完成管理的所有肮脏工作)。现在唯一的麻烦就是需要在Cython中使用大量的deref(self.thisptr)来调用C ++ get / set方法:)。
C ++改变:
class NetInfo
typedef std::shared_ptr<NetInfo> NetInfoShPtr;
class NetInfo {
public:
NetInfo();
NetInfo(NetInfo const& rhs);
virtual ~NetInfo();
...
std::vector<NetInfoShPtr> getBridgedNets() const;
void addBridgedNet(NetInfoShPtr const& ni);
protected:
NetInfoData* data_;
};
Cython改变:
from cython.operator cimport dereference as deref
from libcpp.vector cimport vector
from libcpp.memory cimport shared_ptr
cdef extern from 'NetInfo.h':
ctypedef shared_ptr[NetInfo] NetInfoShPtr
cdef cppclass NetInfo:
NetInfo() except +
NetInfo(NetInfo&) except +
...
vector[NetInfoShPtr] getBridgedNets()
void addBridgedNet(NetInfoShPtr&)
cdef class PyNetInfo:
cdef NetInfoShPtr thisptr
def __cinit__(self, PyNetInfo ni=None):
if ni is not None:
self.thisptr = NetInfoShPtr(new NetInfo(deref(ni.thisptr)))
else:
self.thisptr = new NetInfoShPtr(new NetInfo())
def __dealloc__(self):
self.thisptr.reset() # no del, reset the shared pointer
...
def get_bridged_nets(self):
cdef PyNetInfo r
cdef NetInfoShPtr n
cdef vector[NetInfoShPtr] nets = deref(self.thisptr).getBridgedNets() # Must derefence
result = []
for n in nets:
r = PyNetInfo.__new__(PyNetInfo)
r.thisptr = n
result.append(r)
return result
def add_bridged_net(self, PyNetInfo ni):
deref(self.thisptr).addBridgedNet(ni.thisptr) # Must dereference
答案 1 :(得分:1)
当你这样做时
a.add_bridged_net(x)
未存储对x
的引用,只有指向NetInfo
实例的指针被添加到向量中。由于未引用python对象x
,因此将释放x
,因此指向C ++ NetInfo
实例的对应指针,即向量中将有一个指向已解除分配对象的指针。 / p>