Кто хорошо разбирается в MQL4, помогите с кодом. Указатели. Очистка памяти с помощью delete.

 

У меня есть индикатор. Вкратце, я делаю парсинг json-а и превращаю его в нужный мне массив объектов. Больше в коде индикатора указателей нет (т.е это единственный подобный метод): 

void InitPatternsArray(string json)
{
   JSONParser *prsr = new JSONParser();
   JSONValue *jv = prsr.parse(json);
   JSONObject *jo = jv;
   JSONArray *jarr, *candlArr;
   
   jarr = jo.getArray("patterns"); // это строчка номер 261. 11 символ это если курсор поставить перед jo
   for(int i=0; i<jarr.size(); i++)
   {
      Pattern p;
      p.SetTitle(jarr.getObject(i).getString("title"));
      p.SetId(StrToInteger(jarr.getObject(i).getString("id")));
      
      Candle candles[];
      candlArr = jarr.getObject(i).getArray("candles");
      for(int j=0; j<candlArr.size(); j++)
      {
         Candle c;
         c.SetClose(StringToDouble(candlArr.getObject(j).getString("close")));
         c.SetOpen(StringToDouble(candlArr.getObject(j).getString("open")));
         c.SetHigh(StringToDouble(candlArr.getObject(j).getString("high")));
         c.SetLow(StringToDouble(candlArr.getObject(j).getString("low")));
         c.SetTime(candlArr.getObject(j).getString("time"));
         ArrayPushCandle(candles, c);
      }
      p.SetCandles(candles);
      ArrayPushPattern(patterns, p);
   }

   delete jv;
   delete jarr;
   delete candlArr;
   delete prsr;
}

Когда я запукаю индикатор в обычном режиме в MT4 - все хорошо.
Если запускаю индикатор в дебаге появляется следующия ошибка (delete invalid pointer):
delete invalid pointer


Если запускаю в тестере стратегий вот такая ошибка (invalid pointer access, строчку 261 я пометил, на рисунке выше):

access pointer 

 

Я не pro в MQL и C++. Понимаю, что, вероятно, я что-то где-то некорректно высвобождаю. У меня MT4 Build 988 (от 4-ого июля).
Пытался разобраться сам, но без видимого прогресса.
Спасибо за любую помощь. 

 

В динамической памяти вы создаёте только один объект, адрес которого сохраняете в указателе prsr. В конце функции вы правильно удаляете этот объект. А остальные-то делиты в конце функции что удаляют? Если это тоже объекты в динамической памяти, которые создаются где-то в других методах вашего класса, то код этих методов и надо смотреть, а по приведённому вами фрагменту ничего не понять.

Upd.

iJSmile:

Больше в коде индикатора указателей нет (т.е это единственный подобный метод): 

Да как же нет, если во второй же строчке вашей функции некий метод parse() возвращает указатель? А в дальнейшем - и другие методы (getObject(), getArray()). У вас там указатель указателем погоняет.

И ещё, что бросилось в глаза:

jarr = jo.getArray("patterns"); // это строчка номер 261. 11 символ это если курсор поставить перед jo

... 

candlArr = jarr.getObject(i).getArray("candles");

Как-то вы по-разному вызываете метод getArray в этих строках. Похоже, что в первом случае и впрямь неправильно.

 
iJSmile:

У меня есть индикатор. Вкратце, я делаю парсинг json-а и превращаю его в нужный мне массив объектов. Больше в коде индикатора указателей нет (т.е это единственный подобный метод): 

Когда я запукаю индикатор в обычном режиме в MT4 - все хорошо.
Если запускаю индикатор в дебаге появляется следующия ошибка (delete invalid pointer):


Если запускаю в тестере стратегий вот такая ошибка (invalid pointer access, строчку 261 я пометил, на рисунке выше):

 

 

Я не pro в MQL и C++. Понимаю, что, вероятно, я что-то где-то некорректно высвобождаю. У меня MT4 Build 988 (от 4-ого июля).
Пытался разобраться сам, но без видимого прогресса.
Спасибо за любую помощь. 

Уже давно заметил эту особенность MQL4, но до сих пор никак не дойдут руки до сервисдеска. Нюанс в том, что оператор delete не производит обнуление указателя, как в С++. Т. е. удаление объекта происходит, а указатель по прежнему продолжает содержать не NULL. Поэтому, если возможно повторное обращение к указателю после оператора delete, то делаю так:

delete pointer;
pointer = NULL;
 
Ihor Herasko:

Уже давно заметил эту особенность MQL4, но до сих пор никак не дойдут руки до сервисдеска. Нюанс в том, что оператор delete не производит обнуление указателя, как в С++. Т. е. удаление объекта происходит, а указатель по прежнему продолжает содержать не NULL. Поэтому, если возможно повторное обращение к указателю после оператора delete, то делаю так:

это прямтаки вопрос к сервисдеску С++...у них такие-же нелады :-)

 
Ihor Herasko:

Уже давно заметил эту особенность MQL4, но до сих пор никак не дойдут руки до сервисдеска. Нюанс в том, что оператор delete не производит обнуление указателя, как в С++. Т. е. удаление объекта происходит, а указатель по прежнему продолжает содержать не NULL. Поэтому, если возможно повторное обращение к указателю после оператора delete, то делаю так:

В сях то же самое. Только при чём здесь это? У топикстартера нет двойного удаления. По крайней мере, в приведённом куске кода.

 
Ihor Herasko:

Уже давно заметил эту особенность MQL4, но до сих пор никак не дойдут руки до сервисдеска. Нюанс в том, что оператор delete не производит обнуление указателя, как в С++. Т. е. удаление объекта происходит, а указатель по прежнему продолжает содержать не NULL. Поэтому, если возможно повторное обращение к указателю после оператора delete, то делаю так:

Cпасибо за ответ, Игорь. Вы всегда неравнодушны :). Теперь я знаю про NULL.
Основываясь на вашем совете и совете Сергея, пересмотрел указатели и теперь удаление в конце метода у меня выглядит так (удалил 2 ненужных delete):
   delete jv;
   jv = NULL;
   delete prsr;
   prsr = NULL;
Но, к сожалению, это не решило проблему. Как правильно заметил Сергей в последнем посте, дело видимо все же не в удалении.
 
Sergei Vladimirov:

Да как же нет, если во второй же строчке вашей функции некий метод parse() возвращает указатель? А в дальнейшем - и другие методы (getObject(), getArray()). У вас там указатель указателем погоняет.

Пардон, мне стоило это включить в пост. В моём индикаторе действительно нет больше указателей, но я использую вот эту библиотеку для парсинга json-а. Т.е в индикаторе есть 2 инклюда:

#include "hash.mqh"
#include "json.mqh"

  

Sergei Vladimirov:
И ещё, что бросилось в глаза:

jarr = jo.getArray("patterns"); // это строчка номер 261. 11 символ это если курсор поставить перед jo
...
candlArr = jarr.getObject(i).getArray("candles");

Как-то вы по-разному вызываете метод getArray в этих строках. Похоже, что в первом случае и впрямь неправильно.

Я вызываю по-разному, потому что JSONArray позволяет работать с ним и так и так. Ну на самом деле я все делал по примеру (в ссылке на библиотеку есть пример):
Структура json-а у меня такая:

 {
    "patterns": [
        {
            "id": "1",
            "title": "some title",
            "candles": [
                {
                    "high": "1.11019",
                    "open": "1.11009",
                    "close": "1.10971",
                    "low": "1.10959",
                    "time": "03:25:00"
                },
                {
                    "high": "1.11015",
                    "open": "1.11014",
                    "close": "1.11010",
                    "low": "1.11000",
                    "time": "03:20:00"
                }
            ]
        },
        {
            "id": "2",
            "title": "some title 2",
            "candles": [
                {
                    "high": "1.10901",
                    "open": "1.10899",
                    "close": "1.10852",
                    "low": "1.10829",
                    "time": "05:45:00"
                },
                {
                    "high": "1.10925",
                    "open": "1.10925",
                    "close": "1.10900",
                    "low": "1.10899",
                    "time": "05:40:00"
                }
            ]
        }
    ]
}

Странно то, что эти ошибки вылетают только в тестере и в дебагере (причем и сами ошибки отличаются). Если просто вешаю индикатор на график - в логах ошибок нет и все работает.

 
 
Ihor Herasko:

Уже давно заметил эту особенность MQL4, но до сих пор никак не дойдут руки до сервисдеска. Нюанс в том, что оператор delete не производит обнуление указателя, как в С++. Т. е. удаление объекта происходит, а указатель по прежнему продолжает содержать не NULL. Поэтому, если возможно повторное обращение к указателю после оператора delete, то делаю так:

Покажите мне, где в C++ указатель автоматически обнуляется после операции delete.

По семантике delete указатель является rvalue, но никак не lvalue

 
результат prsr.parse(json) надо проверять. Если у парсера чего-то неполучилось, он вернёт NULL. А вы потом к нему с getObject лезете..
 
Maxim Kuznetsov:

это прямтаки вопрос к сервисдеску С++...у них такие-же нелады :-)

Во всем виноват Страуструп )) Обнуление указателя после delete это undefinete behavior, то есть зависит от компилятора и не является обязательным. VC++ 2015 не обнуляет.
 
Maxim Kuznetsov:
результат prsr.parse(json) надо проверять. Если у парсера чего-то неполучилось, он вернёт NULL. А вы потом к нему с getObject лезете..
1) Проблема с delete invalid pointer решилась когда я почистил ненужные delet-ы по замечаниям Cергея.
2) Т.е сейчас осталась только проблема с тестером стратегий. Я выкачал с гитхаба последнюю версию этого json parsera, они там добавили логирование ошибок. Максим вы правы, в тестере parse() возвращает почему-то NULL. Теперь метод выглядит так:
void InitPatternsArray(string json)
{
   JSONArray *jarr; 
   JSONArray *candlArr;
   
   JSONParser *prsr=new JSONParser();
   JSONValue *jv=prsr.parse(json);
   if(jv==NULL) 
   {
      Print("error: "+(string)prsr.getErrorCode() + " "+ prsr.getErrorMessage());
   } 
   else 
   {
      Print("PARSED:" + jv.toString());
      if(jv.isObject()) 
      {
         JSONObject *jo=jv;
         jarr = jo.getArray("patterns");
         for(int i=0; i<jarr.size(); i++)
         {
            Pattern p;
            p.SetTitle(jarr.getObject(i).getString("title"));
            p.SetId(StrToInteger(jarr.getObject(i).getString("id")));
      
            Candle candles[];
            candlArr = jarr.getObject(i).getArray("candles");
            for(int j=0; j<candlArr.size(); j++)
            {
               Candle c;
               c.SetClose(StringToDouble(candlArr.getObject(j).getString("close")));
               c.SetOpen(StringToDouble(candlArr.getObject(j).getString("open")));
               c.SetHigh(StringToDouble(candlArr.getObject(j).getString("high")));
               c.SetLow(StringToDouble(candlArr.getObject(j).getString("low")));
               c.SetTime(candlArr.getObject(j).getString("time"));
               ArrayPushCandle(candles, c);
            }
            p.SetCandles(candles);
            ArrayPushPattern(patterns, p);
         }
      }
   }

   delete jv;
   jv = NULL;
   delete prsr;
   prsr = NULL;
}


 А тестер выдает это:

second err