我正在尝试理解C ++ / CLI,因此我可以为C ++代码创建Wrapper类。我的问题是我有一个类存储指向该类的父对象的指针,因此我需要将它传递给该类。
下面是一个示例,但完整的类具有更多功能并存储额外数据。
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());
}
}
虽然这适用于类中的函数,但是如果我想创建一个对象或者我有一个需要传入非托管类的函数,我仍然会遇到问题。
我有办法解决这个问题吗?
答案 0 :(得分:2)
ManagedA^ GetParent()
{
return gcnew ManagedA(unmanaged->GetParent());
}
你用这样的代码射击你的腿,非常危险。问题是,您正在创建多个ManagedA对象,这些对象引用完全相同的A *。一旦一个被破坏,所有其他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 ^。这需要静态Dictionary<IntPtr, ManagedA^>
。在构造函数中将对象添加到字典中,在终结器中删除它们。请注意,您忘记包含终结器,但它不是可选的。我把它添加到了代码段。