[执行存储的回调时发生System.AccessViolationException错误

问题描述 投票:0回答:1

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

// 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进程接收到数据时可以调用它。当此数据到达时,事件被引发,并从事件方法中调用回调。此时,我收到以下异常:

未处理的异常:System.AccessViolationException:尝试执行以下操作:读取或写入受保护的内存。这通常表明其他内存已损坏。在Iface.Wrapper.ReturnToCallback(Int32数据)

我认为我需要管理std :: function的生存期,我不知道托管类所指向的函数对象的生存期。该对象似乎已删除,托管类保留了悬空的指针。

c++ callback c++-cli access-violation object-lifetime
1个回答
1
投票

我认为我需要管理std::function的生命周期>

是的,当我告诉您将指针存储在托管包装中时,我也告诉过您很多,here

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

std::function是本机对象,并遵循本机C ++规则。将指针放在托管包装器中不会使其被垃圾回收。

该对象似乎已删除,托管类保持悬空指针。

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

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

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

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

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

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

~Wrapper()
{
    delete callback;
    callback = nullptr;
}
© www.soinside.com 2019 - 2024. All rights reserved.