System.AccessViolationException 执行存储的回调时出错
System.AccessViolationException error when stored callback is executed
我已经通过 C++/CLI 包装器将 C++ 成员函数 作为回调传递给 C# 项目(这很好用)。当从另一个 .exe 进程接收数据时,C# 项目将调用此委托:将引发一个事件,一个方法将调用此回调。因此,我需要使用已创建的 C# class 静态实例 "save" 此 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 进程接收到数据时能够在之后调用它。当此数据到达时,将引发 事件并从事件方法 调用回调。正是在这一点上,我得到以下异常:
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::function 的生命周期,我不知道托管 class 指向的函数对象的生命周期。该对象似乎已被删除,托管 class 留下一个悬挂指针。
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.
std::function
是本机对象并遵循本机 C++ 规则。将指针放在托管包装器中不会使其成为垃圾收集器。
The object seems to be deleted and the managed class is left holding a dangling pointer.
是的,您的术语不准确,但您已正确诊断出问题。看看:
void dispatchEvent(std::function<void(int)> processEvent)
{
Iface::Wrapper wrapper;
wrapper.callback = &processEvent;
wrapper.PassCallback();
}
processEvent
是函数参数,一个std::function
对象按值传递。创建并存储在参数中的副本一直存在到范围结束。它具有自动存储期限。当函数returns时,所有局部变量,包括函数参数,都被销毁(不是"deleted")。
您需要动态分配 std::function
对象(的副本),例如:
typedef std::function<void(int)> cbfn;
wrapper.callback = new cbfn(processEvent);
现在你有内存泄漏,但至少在它被销毁后你没有使用该对象。如果您只制作少数这些物体,泄漏甚至可能是可以接受的。通常,您应该在包装器上实现 IDisposable
并让 Dispose
方法执行 delete callback;
。在 C++/CLI 中,您使用析构函数语法来完成此操作。
~Wrapper()
{
delete callback;
callback = nullptr;
}
我已经通过 C++/CLI 包装器将 C++ 成员函数 作为回调传递给 C# 项目(这很好用)。当从另一个 .exe 进程接收数据时,C# 项目将调用此委托:将引发一个事件,一个方法将调用此回调。因此,我需要使用已创建的 C# class 静态实例 "save" 此 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 进程接收到数据时能够在之后调用它。当此数据到达时,将引发 事件并从事件方法 调用回调。正是在这一点上,我得到以下异常:
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::function 的生命周期,我不知道托管 class 指向的函数对象的生命周期。该对象似乎已被删除,托管 class 留下一个悬挂指针。
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.
std::function
是本机对象并遵循本机 C++ 规则。将指针放在托管包装器中不会使其成为垃圾收集器。
The object seems to be deleted and the managed class is left holding a dangling pointer.
是的,您的术语不准确,但您已正确诊断出问题。看看:
void dispatchEvent(std::function<void(int)> processEvent)
{
Iface::Wrapper wrapper;
wrapper.callback = &processEvent;
wrapper.PassCallback();
}
processEvent
是函数参数,一个std::function
对象按值传递。创建并存储在参数中的副本一直存在到范围结束。它具有自动存储期限。当函数returns时,所有局部变量,包括函数参数,都被销毁(不是"deleted")。
您需要动态分配 std::function
对象(的副本),例如:
typedef std::function<void(int)> cbfn;
wrapper.callback = new cbfn(processEvent);
现在你有内存泄漏,但至少在它被销毁后你没有使用该对象。如果您只制作少数这些物体,泄漏甚至可能是可以接受的。通常,您应该在包装器上实现 IDisposable
并让 Dispose
方法执行 delete callback;
。在 C++/CLI 中,您使用析构函数语法来完成此操作。
~Wrapper()
{
delete callback;
callback = nullptr;
}