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

时间:2018-03-23 02:02:12

标签: pointers c++-cli unmanaged managed

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

非托管层中的类具有查询方法,假设UnmanagedA :: B()返回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;
}

1 个答案:

答案 0 :(得分:0)

这是使用智能指针的典型案例。

所以不要存储UnmanagedA *和UnmanagedB *使用shared_ptr和shared_ptr

Becaus ethe托管类只能携带一个普通指针,指向一个非法的类,你必须再次重定向它并使用:

shared_ptr<UnmanagedA>* pManagedA;

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

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

指向非托管类的所有普通指针都应该是shared_ptr实例。在您的主要使用make_shared而不是new。或者将new创建的指针指向shared_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; }
};