我试图理解c++/CLI,所以我可以为c++代码创建包装器类。我的问题是,我有一个类,它存储一个指针到该类的父对象,因此我需要传递它到类。
下面是一个例子,但是完整的类有更多的函数和存储额外的数据。
class A
{
private:
A* parent;
public:
A(A* Parent)
{
parent = Parent;
}
~A()
{
delete parent;
}
A* GetParent()
{
return parent;
}
}
我目前的想法是有一个非公共构造函数,这样你就可以用非托管类构造一个托管类,而不需要在类外访问它。
public ref class ManagedA
{
A* unmanaged;
ManagedA(A* unmanaged)
{
this->unmanaged = unmanaged;
}
public:
ManagedA(ManagedA^ Parent)
{
unmanaged = new A(Parent->unmanaged);
}
~ManagedA()
{
delete unmanaged;
unmanaged = NULL;
}
ManagedA^ GetParent()
{
return gcnew ManagedA(unmanaged->GetParent());
}
}
虽然这适用于类内的函数,但如果我想创建一个对象,或者如果我有一个需要传入非托管类的函数,我仍然会遇到问题。
有什么办法可以解决这个问题吗?
ManagedA^ GetParent()
{
return gcnew ManagedA(unmanaged->GetParent());
}
你写这样的代码是在玩火自焚,这是非常危险的。问题是,您正在创建引用完全相同A*的多个ManagedA对象。一旦中的一个被销毁,所有其他ManagedA对象现在都有一个悬浮指针。这几乎肯定会导致内存损坏。
解决方法很简单,只需将父引用存储在构造函数中:
public ref class ManagedA {
private:
A* unmanaged;
ManagedA^ parent;
public:
ManagedA(ManagedA^ Parent) : parent(Parent) {
A* unmanagedParent = Parent == nullptr ? nullptr : Parent->unmanaged;
unmanaged = new A(unmanagedParent);
}
ManagedA^ GetParent() {
return parent;
}
~ManagedA() {
this->!ManagedA();
unmanaged = NULL;
}
!ManagedA() {
delete unmanaged;
}
};
注意构造函数中添加的nullptr检查,这是我可以看到如何创建第一个A*的唯一相同方式。
这是一种简单的情况,当您需要将A*映射回ManagedA^时,会出现完全相同的对象标识问题。首先检查是否真的需要,客户端代码应该只操作ManagedA对象。必要时,您需要创建一个查找表,以便能够可靠地找到相应的ManagedA^ back。这需要一个静态的Dictionary<IntPtr, ManagedA^>
。在构造函数中向字典中添加对象,在终结器中删除对象。注意,您忘了包含终结器,它不是可选的。我将它添加到代码片段中。