执行存储的回调时发生System.AccessViolationException错误 [英] System.AccessViolationException error when stored callback is executed

查看:185
本文介绍了执行存储的回调时发生System.AccessViolationException错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已通过C ++ / CLI包装器将 C ++成员函数作为回调传递给C#项目(这很好)。当从另一个.exe进程接收数据时,C#项目将调用此委托:将引发一个事件,一个方法将调用此回调。因此,我需要使用已经创建的C#类的静态实例保存此Action委托。我得到以下代码:

I have passed as callback a C++ member function to a C# project through a C++/CLI wrapper (this works fine). The C# project is going to call this delegate when receiving data from another .exe process: an event will be raised and a method will call this callback. So, I needed to "save" this Action delegate using an static instance of a C# class already created. I got the following code:

// C++ unmanaged function
WRAPPER_API void dispatchEvent(std::function<void(int)> processEvent)
{
    Iface::Wrapper wrapper;
    wrapper.callback = &processEvent;
    wrapper.PassCallback();
}

//C++ Managed
    public ref class Wrapper
    {
    public:
        std::function<void(int)>* callback;

        void ReturnToCallback(int data)
        {
            (*callback)(data);
        }
        void PassCallback()
        {
            StartGenerator^ startGen = gcnew StartGenerator(gcnew Action<int>(this, &Wrapper::ReturnToCallback));
        }
    };

// C# 
public class StartGenerator
{
    private Communication comm;

    public StartGenerator(Action<int> callback)
    {
        comm = Communication.Instance;
        comm.callback = callback;
    }
}

如果我在StartGenerator方法中调用Action委托, C ++函数已正确执行。但是,我的目标是保存委托以便以后从另一个.exe进程接收到数据时可以调用它。当这些数据到达时,会引发一个事件,并从事件方法中调用回调。此时,我收到以下异常:

If I call the Action delegate in StartGenerator method, the C++ function is properly executed. However, my goal was saving the delegate to be able to call it afterwards, when data is received from another .exe process. When this data arrives, an event is raised and callback is called from the event method. It is at this point when I get the following exception:


未处理的异常:System.AccessViolationException:尝试对
进行读写受保护的内存。这通常表明其他
内存已损坏。在
Iface.Wrapper.ReturnToCallback(Int32数据)

Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt. at Iface.Wrapper.ReturnToCallback(Int32 data)

我认为我需要管理std的生命周期::函数,我不知道托管类所指向的函数对象的生存期。

I think I need to manage the lifetime of the std::function, I don't know about the lifetime of the function object being pointed to by the managed class. The object seems to be deleted and the managed class is left holding a dangling pointer.

推荐答案


I认为我需要管理 std :: function

,当您告诉我将指针存储在托管包装中时,我也告诉过您很多,请此处

Yes, I told you as much when I told you to store a pointer in the managed wrapper, here


我不知道托管类所指向的功能对象的寿命。

I don't know about the lifetime of the function object being pointed to by the managed class.

std :: function 是本机对象,并遵循本机C ++规则。

The std::function is a native object and follows the native C++ rules. Putting a pointer in a managed wrapper won't make it garbage-collected.


该对象似乎已删除,并且保留了托管类

The object seems to be deleted and the managed class is left holding a dangling pointer.

是的,您的术语不准确,但您已经正确诊断了问题。看看:

Yes, your terminology isn't exact but you've correctly diagnosed the problem. Take a look:

void dispatchEvent(std::function<void(int)> processEvent)
{
    Iface::Wrapper wrapper;
    wrapper.callback = &processEvent;
    wrapper.PassCallback();
}

processEvent 是函数参数,按值传递的 std :: function 对象。在参数中创建并存储的副本将一直保留到作用域结尾。它具有自动存储期限。当函数返回时,所有局部变量(包括函数参数)都将被销毁(而不是删除)。

processEvent is function argument, a std::function object passed by value. The copy made and stored in the argument lives until the end of scope. It has automatic storage duration. When the function returns, all the local variables, function arguments included, are destroyed (not "deleted").

您将需要动态分配( std :: function 对象,例如:

You will need to dynamically allocate (a copy of) the std::function object, like:

typedef std::function<void(int)> cbfn;
wrapper.callback = new cbfn(processEvent);

现在您发生了内存泄漏,但是至少在对象被销毁后您没有使用它。如果仅使这些对象很少,则泄漏甚至可以接受。通常,应该在包装器上实现 IDisposable 并使用 Dispose 方法执行 delete回调; 。在C ++ / CLI中,您可以使用析构函数语法来实现这一点。

Now you have a memory leak, but at least you aren't using the object after it's destroyed. If you only make a handful of these objects the leak might even be acceptable. In general, you should implement IDisposable on your wrapper and have the Dispose method do delete callback;. In C++/CLI you use destructor syntax to accomplish that.

~Wrapper()
{
    delete callback;
    callback = nullptr;
}

这篇关于执行存储的回调时发生System.AccessViolationException错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆