C++/CLI:将同一个非托管对象包装在多个托管对象中
C++/CLI: wrapping the same unmanaged object in multiple managed objects
我正在开发一个有两层的库,非托管 (C++) 和托管 (C++/CLI)。非托管层包含逻辑和计算算法,而托管层为基于 .NET 的主机应用程序提供接口和可视化。托管层中的 class 将其对应的 class 包装在非托管层中,例如ManagedA 包装 UnmanagedA,ManagedB 包装 UnmanagedB。
类在非托管层有查询方法,假设UnmanagedA::B() returns是UnmanagedB的一个实例。为了可视化,我需要将此实例包装在 ManagedB 实例中。问题是,如果我重复此过程两次,我将创建两个指向同一个 UnmanagedB 实例的 ManagedB 实例。因为 ManagedB 实例被释放,同一个 UnmanagedB 实例被删除了两次,这是不应该发生的。
所以我想知道将非托管对象包装在托管对象中的最佳实践或策略。
这是模拟此行为的代码。我知道您不需要显式删除托管对象,但我在这里使用它只是为了模拟删除顺序。
非常感谢。
#include "stdafx.h"
using namespace System;
class UnmanagedB
{
public:
UnmanagedB() {}
~UnmanagedB() {}
int i = 0;
};
class UnmanagedA
{
public:
UnmanagedA(UnmanagedB* pUnmanagedB)
: m_pUnmanagedB(pUnmanagedB)
{
}
~UnmanagedA() {}
UnmanagedB* B() { return m_pUnmanagedB; }
protected:
UnmanagedB* m_pUnmanagedB;
};
public ref class ManagedA : IDisposable
{
public:
ManagedA(UnmanagedA* pUnmanagedA)
: m_pUnmanagedA(pUnmanagedA)
{
}
~ManagedA()
{
delete m_pUnmanagedA;
}
private:
UnmanagedA* m_pUnmanagedA;
};
public ref class ManagedB : IDisposable
{
public:
ManagedB(UnmanagedB* pUnmanagedB)
: m_pUnmanagedB(pUnmanagedB)
{
}
~ManagedB()
{
delete m_pUnmanagedB;
}
private:
UnmanagedB * m_pUnmanagedB;
};
int main(array<System::String ^> ^args)
{
UnmanagedB* pUnmanagedB = new UnmanagedB();
UnmanagedA* pUnmanagedA = new UnmanagedA(pUnmanagedB);
ManagedB^ pManagedB1 = gcnew ManagedB(pUnmanagedA->B());
ManagedB^ pManagedB2 = gcnew ManagedB(pUnmanagedA->B());
delete pManagedB1;
delete pManagedB2; // will crash here because the destructor deletes pUnmanagedB, which is already deleted in the previous line
delete pUnmanagedA;
return 0;
}
这是使用智能指针的典型案例。
所以不要存储 UnmanagedA* 和 UnmanagedB* 使用 shared_ptr 和 shared_ptr
因为托管的 class 只能携带指向未托管的 class 的普通指针,您必须再次重定向它并使用:
shared_ptr<UnmanagedA>* pManagedA;
一个简单的访问器函数将帮助您使用指针:
shared_ptr<UnmanagedA> GetPtrA() { return *pManagedA; }
所有指向非托管 classes 的普通指针应该是 shared_ptr 个实例。在你主要使用 make_shared 而不是 new 。或者将new创建的指针指向一个shared_ptr...
这是一个 class 重写:
public ref class ManagedA : IDisposable
{
public:
ManagedA(shared_ptr<UnmanagedA> pUnmanagedA)
{
m_pUnmanagedA = new shared_ptr<UnmanagedA>();
*m_pUnmanagedA = pUnmanagedA;
}
~ManagedA()
{
delete m_pUnmanagedA;
}
void Doit()
{
GetPtrA()->DoSomething();
}
private:
shared_ptr<UnmanagedA>* m_pUnmanagedA;
shared_ptr<UnmanagedA> GetPtrA() { return *m_pUnmanagedA; }
};
我正在开发一个有两层的库,非托管 (C++) 和托管 (C++/CLI)。非托管层包含逻辑和计算算法,而托管层为基于 .NET 的主机应用程序提供接口和可视化。托管层中的 class 将其对应的 class 包装在非托管层中,例如ManagedA 包装 UnmanagedA,ManagedB 包装 UnmanagedB。
类在非托管层有查询方法,假设UnmanagedA::B() returns是UnmanagedB的一个实例。为了可视化,我需要将此实例包装在 ManagedB 实例中。问题是,如果我重复此过程两次,我将创建两个指向同一个 UnmanagedB 实例的 ManagedB 实例。因为 ManagedB 实例被释放,同一个 UnmanagedB 实例被删除了两次,这是不应该发生的。
所以我想知道将非托管对象包装在托管对象中的最佳实践或策略。
这是模拟此行为的代码。我知道您不需要显式删除托管对象,但我在这里使用它只是为了模拟删除顺序。
非常感谢。
#include "stdafx.h"
using namespace System;
class UnmanagedB
{
public:
UnmanagedB() {}
~UnmanagedB() {}
int i = 0;
};
class UnmanagedA
{
public:
UnmanagedA(UnmanagedB* pUnmanagedB)
: m_pUnmanagedB(pUnmanagedB)
{
}
~UnmanagedA() {}
UnmanagedB* B() { return m_pUnmanagedB; }
protected:
UnmanagedB* m_pUnmanagedB;
};
public ref class ManagedA : IDisposable
{
public:
ManagedA(UnmanagedA* pUnmanagedA)
: m_pUnmanagedA(pUnmanagedA)
{
}
~ManagedA()
{
delete m_pUnmanagedA;
}
private:
UnmanagedA* m_pUnmanagedA;
};
public ref class ManagedB : IDisposable
{
public:
ManagedB(UnmanagedB* pUnmanagedB)
: m_pUnmanagedB(pUnmanagedB)
{
}
~ManagedB()
{
delete m_pUnmanagedB;
}
private:
UnmanagedB * m_pUnmanagedB;
};
int main(array<System::String ^> ^args)
{
UnmanagedB* pUnmanagedB = new UnmanagedB();
UnmanagedA* pUnmanagedA = new UnmanagedA(pUnmanagedB);
ManagedB^ pManagedB1 = gcnew ManagedB(pUnmanagedA->B());
ManagedB^ pManagedB2 = gcnew ManagedB(pUnmanagedA->B());
delete pManagedB1;
delete pManagedB2; // will crash here because the destructor deletes pUnmanagedB, which is already deleted in the previous line
delete pUnmanagedA;
return 0;
}
这是使用智能指针的典型案例。
所以不要存储 UnmanagedA* 和 UnmanagedB* 使用 shared_ptr 和 shared_ptr
因为托管的 class 只能携带指向未托管的 class 的普通指针,您必须再次重定向它并使用:
shared_ptr<UnmanagedA>* pManagedA;
一个简单的访问器函数将帮助您使用指针:
shared_ptr<UnmanagedA> GetPtrA() { return *pManagedA; }
所有指向非托管 classes 的普通指针应该是 shared_ptr 个实例。在你主要使用 make_shared 而不是 new 。或者将new创建的指针指向一个shared_ptr...
这是一个 class 重写:
public ref class ManagedA : IDisposable
{
public:
ManagedA(shared_ptr<UnmanagedA> pUnmanagedA)
{
m_pUnmanagedA = new shared_ptr<UnmanagedA>();
*m_pUnmanagedA = pUnmanagedA;
}
~ManagedA()
{
delete m_pUnmanagedA;
}
void Doit()
{
GetPtrA()->DoSomething();
}
private:
shared_ptr<UnmanagedA>* m_pUnmanagedA;
shared_ptr<UnmanagedA> GetPtrA() { return *m_pUnmanagedA; }
};