托管类中的非托管结构实例

发布于 2024-09-03 04:43:09 字数 355 浏览 10 评论 0原文

我有一个相当具体的问题,我已经困扰了几天了。

我使用的是本机 C++,其中一种方法将 ptr 指向包含固定大小的 char 数组的结构。

例如

struct userData {
    char data1[10];
    char data2[10];
};

方法:

short AddItem(long id, userData* data);

我试图从托管 VC++ 中调用此方法,但我需要有一个可以在托管类中保留的 userData 实例。

任何人都可以帮助如何实现这一目标吗?

谢谢

I've got a fairly specific problem i've been struggling with for a couple of days.

I'm using a native C++, one of the methods takes a ptr to a struct containing fixed size char arrays.

e.g.

struct userData {
    char data1[10];
    char data2[10];
};

method:

short AddItem(long id, userData* data);

I'm trying to call to call this from Managed VC++ but I need to have an instance of userData I can keep hold of in my managed class.

Can anyone help with how to achieve this?

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

薄情伤 2024-09-10 04:43:09

当首选与垃圾收集进行友好互操作时,我使用以下两个容器之一:

template<typename T> ref class GcPlainPtr sealed {
    T*  ptr;
public:
    GcPlainPtr(T*ptr): ptr(ptr) { GC::AddMemoryPressure(sizeof(T)); }

    !GcPlainPtr() { 
        GC::RemoveMemoryPressure(sizeof(T)); 
        delete ptr; ptr = nullptr; 
    }

    ~GcPlainPtr() { this->!GcPlainPtr(); } //mostly just to avoid C4461

    T* get() {return ptr;}

    static T* operator->(GcPlainPtr<T>% gcPtr) { return gcPtr.ptr;}
    static operator T*(GcPlainPtr<T>% gcPtr) { return gcPtr.ptr; }
};

前一个容器看起来足以满足您的需求。您可以如下使用:

ref class MyManagedClass {
    GcPlainPtr<userData> myUserData;

    MyManagedClass(...bla...) 
        : myUserData(new userData(...)) 
        , ... 
    {...}

    AnotherMethod() {
        std::cout << myUserData->data1 << '\n';
        AddItem(1, myUserData.get());
    }
}

前一种方法的优点是,即使您忘记处置对象,内存压力也会得到合理更新,以便垃圾收集以适当的频率发生。

如果您大致知道要分配的数据元素的大小,但它不仅仅是直接大小(即本机结构或类在内部分配内存),则以下变体可能更合适:

template<typename T> ref class GcAutoPtr sealed {
    T*  ptr;
    size_t  size;
public:
    GcAutoPtr(T*ptr,size_t size) : ptr(ptr), size(size) { 
        GC::AddMemoryPressure(size);
    }

    !GcAutoPtr() {
        GC::RemoveMemoryPressure(size);
        size=0;
        delete ptr;
        ptr = nullptr;
    }

    ~GcAutoPtr() { this->!GcAutoPtr();} //mostly just to avoid C4461

    T* get() {return ptr;}

    static T* operator->(GcAutoPtr<T>% gcPtr) { return gcPtr.ptr;}
    static operator T*(GcAutoPtr<T>% gcPtr) { return gcPtr.ptr; }
};

I use one of the following two containers when friendly interop with garbage collection is preferred:

template<typename T> ref class GcPlainPtr sealed {
    T*  ptr;
public:
    GcPlainPtr(T*ptr): ptr(ptr) { GC::AddMemoryPressure(sizeof(T)); }

    !GcPlainPtr() { 
        GC::RemoveMemoryPressure(sizeof(T)); 
        delete ptr; ptr = nullptr; 
    }

    ~GcPlainPtr() { this->!GcPlainPtr(); } //mostly just to avoid C4461

    T* get() {return ptr;}

    static T* operator->(GcPlainPtr<T>% gcPtr) { return gcPtr.ptr;}
    static operator T*(GcPlainPtr<T>% gcPtr) { return gcPtr.ptr; }
};

The previous container looks sufficient for your needs. You can use it as follows:

ref class MyManagedClass {
    GcPlainPtr<userData> myUserData;

    MyManagedClass(...bla...) 
        : myUserData(new userData(...)) 
        , ... 
    {...}

    AnotherMethod() {
        std::cout << myUserData->data1 << '\n';
        AddItem(1, myUserData.get());
    }
}

The advantage of the previous approach is that even if you forget to dispose of the objects, the memory pressure is reasonably updated so that garbage collection occurs at the appropriate frequency.

If you know the size of the data element you're allocating roughtly, but it's not merely the direct size (i.e. the native struct or class allocates memory internally), the following variant may be more appropriate:

template<typename T> ref class GcAutoPtr sealed {
    T*  ptr;
    size_t  size;
public:
    GcAutoPtr(T*ptr,size_t size) : ptr(ptr), size(size) { 
        GC::AddMemoryPressure(size);
    }

    !GcAutoPtr() {
        GC::RemoveMemoryPressure(size);
        size=0;
        delete ptr;
        ptr = nullptr;
    }

    ~GcAutoPtr() { this->!GcAutoPtr();} //mostly just to avoid C4461

    T* get() {return ptr;}

    static T* operator->(GcAutoPtr<T>% gcPtr) { return gcPtr.ptr;}
    static operator T*(GcAutoPtr<T>% gcPtr) { return gcPtr.ptr; }
};
挽清梦 2024-09-10 04:43:09

您无法将实例存储在托管类对象中并轻松生成指向它的指针。这与垃圾收集器非常不兼容。当它压缩堆时,它会移动托管对象,这可能会在不可预测的时间发生。尝试将指针传递给 userData 成员将生成编译器错误。

一些解决方法:使用 new 在堆上分配 userData 实例,将指针存储在托管对象中。然而,这是相当低效的,您需要实现一个析构函数和一个终结器来释放它。仅当您希望拥有有限数量的托管类实例时才执行此操作。

下一个解决方案是使用 pin_ptr<> 在调用时生成指针。这会将托管对象固定在内存中,从而防止垃圾收集器移动它。当然效率不是很高。

最后,您可以在进行调用的方法中将 userData 的实例声明为局部变量,并将托管对象中的实例复制到其中。生成指向堆栈变量的指针没有问题,它们无法移动。现在,您还可以按照您想要的方式自由地在托管类中声明结构。假设这个结构不太大,这就是我会选择的。

You cannot store the instance in the managed class object and generate a pointer to it easily. That's very incompatible with the garbage collector. It will move managed objects around when it compacts the heap, that can happen at unpredictable times. Trying to pass a pointer to a userData member will generate a compiler error.

Some workarounds: allocate the userData instance on the heap with new, store the pointer in the managed object. That is however pretty inefficient, you'll need to implement a destructor and a finalizer to release it. Do this only if you expect to have a limited number of instances of the managed class.

Next solution is to generate the pointer at the time of the call, using pin_ptr<>. That pins the managed object in memory, preventing the garbage collector from moving it. Not terribly efficient of course.

Finally, you could declare an instance of userData as a local variable in the method that makes the call and copy the one in the managed object into it. No problem generating pointers to stack variables, they cannot move. You are now also free to declare the structure in your managed class whichever way you want. Assuming this struct isn't too large, that's what I would pick.

一张白纸 2024-09-10 04:43:09

在托管类中存储指向数据的指针,在析构函数中将其删除。

ref class MyManagedClass
{
    userData *myUserData;

public:
    ~MyManagedClass()
    {
        if (myUserData)
            delete myUserData;
        myUserData = NULL;
    }

    short AddItem(long id, userData* data)
    {
        if (myUserData)
            delete myUserData;
        myUserData = new userData(*data);
    }
}

Store a pointer to the data in the managed class, delete it in the destructor.

ref class MyManagedClass
{
    userData *myUserData;

public:
    ~MyManagedClass()
    {
        if (myUserData)
            delete myUserData;
        myUserData = NULL;
    }

    short AddItem(long id, userData* data)
    {
        if (myUserData)
            delete myUserData;
        myUserData = new userData(*data);
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文