代码之家  ›  专栏  ›  技术社区  ›  John Atangwa

C++/CLI:将同一个非托管对象包装到多个托管对象中

  •  0
  • John Atangwa  · 技术社区  · 6 年前

    我正在开发一个具有两层的库,非托管(C++)和托管(C++/CLI)。非托管层包含逻辑和计算算法,而托管层为提供接口和可视化。基于NET的主机应用程序。托管层中的类将其对应的类包装在非托管层中,例如ManagedA包装UnmanagedA,ManagedB包装UnmanagedB。

    非托管层中的类具有查询方法,假设UnmanagedA::B()返回UnmanagedB的实例。为了可视化,我需要将此实例包装在ManagedB实例中。问题是,如果重复此过程两次,我将创建两个指向同一个非ManagedB实例的ManagedB实例。由于ManagedB实例已被释放,因此同一个非ManagedB实例将被删除两次,这是不应该发生的。

    所以 我想知道在托管对象中封装非托管对象的最佳实践或策略。

    下面是模拟此行为的代码。我知道您不需要显式删除托管对象,但我在这里使用它只是为了模拟删除序列。

    非常感谢。

    #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;
    }
    
    1 回复  |  直到 6 年前
        1
  •  0
  •   xMRi    6 年前

    这是使用智能指针的典型情况。

    因此,不要存储UnmanagedA*和UnmanagedB*使用shared\u ptr和shared\u ptr

    由于托管类只能携带指向未托管类的普通指针,因此必须再次重定向该类并使用:

    shared_ptr<UnmanagedA>* pManagedA;
    

    一个简单的访问器函数将帮助您使用指针:

    shared_ptr<UnmanagedA> GetPtrA() { return *pManagedA; }
    

    所有指向非托管类的普通指针都应该是shared\u ptr实例。在您的主要用途中,使用共享而不是新建。或者将new创建的指针指向shared\u ptr。。。

    下面是一个重写的类:

    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; }
    };