Ошибка System.AccessViolationException при выполнении сохраненного обратного вызова - PullRequest
0 голосов
/ 12 апреля 2020

Я передал в качестве обратного вызова членскую функцию C ++ в проект C# через оболочку C ++ / CLI (это прекрасно работает). Проект C# будет вызывать этот делегат при получении данных от другого процесса .exe: будет вызвано событие, и метод вызовет этот обратный вызов. Итак, мне нужно было «сохранить» этот делегат Action, используя stati c экземпляр уже созданного класса C#. Я получил следующий код:

// 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;
    }
}

Если я вызываю делегат Action в методе StartGenerator, функция C ++ выполняется правильно. Однако моя цель состояла в том, чтобы сохранить делегата, чтобы иметь возможность впоследствии вызывать его, когда данные получены из другого процесса .exe. Когда эти данные поступают, возникает событие и вызывается обратный вызов из метода события . Именно в этот момент я получаю следующее исключение:

Необработанное исключение: System.AccessViolationException: Попытка чтения или записи в защищенную память. Это часто указывает на то, что другая память повреждена. at Iface.Wrapper.ReturnToCallback (данные Int32)

Я думаю, что мне нужно управлять временем жизни std :: function, я не знаю о времени жизни объекта функции, на который указывает управляемый класс. Кажется, что объект удален, а управляемый класс остается с висящим указателем.

1 Ответ

1 голос
/ 13 апреля 2020

Я думаю, что мне нужно управлять временем жизни std::function

Да, я говорил вам столько же, когда говорил вам сохранить указатель в управляемой оболочке, здесь

Я не знаю о времени жизни объекта функции, на который указывает управляемый класс.

std::function является нативным объект и следует родным правилам C ++. Помещение указателя в управляемую оболочку не сделает его сборщиком мусора.

Кажется, что объект удален, а управляемый класс остается с висящим указателем.

Да, ваша терминология не точна, но вы правильно диагностировали проблему. Взгляните:

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

processEvent - аргумент функции, объект std::function, переданный по значению. Копия, сделанная и сохраненная в аргументе, действует до конца области видимости. Имеет автомат c срок хранения. Когда функция возвращается, все локальные переменные, включая аргументы функции, уничтожаются (не «удаляются»).

Вам потребуется динамически выделить (копию) объекта std::function, например:

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

Теперь у вас утечка памяти, но, по крайней мере, вы не используете объект после его уничтожения. Если вы сделаете только несколько таких объектов, утечка может быть даже приемлемой. В общем случае вы должны реализовать IDisposable в своей оболочке и иметь метод Dispose do delete callback;. В C ++ / CLI вы используете синтаксис деструктора для выполнения sh этого.

~Wrapper()
{
    delete callback;
    callback = nullptr;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...