Почему эта D-программа выдает странное исключение нарушения доступа? - PullRequest
2 голосов
/ 11 июня 2019

При запуске следующей программы происходит сбой со странным исключением:

"Исключение, выданное в 0x00B31028 в dfun.exe: 0xC0000005: Место чтения нарушения доступа 0x00000000."

Я собираю в visual studio с помощью visuald и dmd. Не уверен в дополнительной информации, чтобы дать, спросите ...

module dfun;

import std.stdio;

class Event(Args...)
{
    private void function(Args)[] _funcArray;

    public this()
    {
    }

    public void addHandler(void function(Args) handler)
    {
        _funcArray.length++;
        _funcArray[$ - 1] = handler;
    }

    public void opCall(Args args)
    {
        foreach(func; _funcArray)
        {
            func(args);
        }
    }
}

void foo(int a, char c)
{
    writeln(a, c);
}

int main()
{
    Event!(int, char) doIt;
    doIt.addHandler(&foo);

    doIt(5, 'a');

    readln();
    return 0;
}

Но если код изменяется на этот, с той же базовой функциональностью:

module dfun;

import std.stdio;

void foo(int a, char c)
{
    writeln(a, c);
}

int main()
{
      //Event!(int, char) doIt;
      //doIt.addHandler(&foo);

      void function(int, char)[] func;

      func.length++;

      func[0] = &foo;

      func[0](5, 'a');

      readln();
      return 0;
}

Работает просто отлично. Что ломает класс?

1 Ответ

4 голосов
/ 11 июня 2019

Вы не инициализируете событие в следующих строках:

Event!(int, char) doIt;
doIt.addHandler(&foo);

Классы являются ссылочными типами и имеют null в качестве начального значения (.init).Это означает, что вам нужно явно инициализировать doIt:

Event!(int, char) doIt = new Event!(int, char)();

Это можно сделать несколько короче, используя auto:

auto doIt = new Event!(int, char);

Это должно решить эту проблему.Один вопрос здесь: Event должен быть классом и иметь семантику ссылок, или структура будет работать так же хорошо для ваших целей?Если бы вы могли использовать структуру, вам не нужно было бы ее инициализировать.

В вашей addHandler function есть еще один крошечный придира: вам не нужен танец ++length; arr[$-1] - D имеет конкатенацию оператор ~ :

public void addHandler(void function(Args) handler)
{
    _funcArray ~= handler;
}
...