Undeleted objects left, leaked memory!

 

Hi

I'm new to MQL. I have an EA, and after it stops, I see the following in the Experts tab:

"9 undeleted objects left

9 objects of type CDynamicArray left

5760 bytes of leaked memory"


I have done some research and looked at similar posts. I know that I have to de-allocate the memory every time I use the keyword "new", however, as you can see in the code below, I have tried that by using delete after I am done with the variable. However the problem persists. What I want to achieve is having a HashMap with the key being a string, and the value being a CDynamicArray. The HashMap is produced and populated in TimeManager.mqh and needs to store its values and be available as long as the program is running. I know I should de-allocate/delete all the CDynamicArray variables before the EA is stopped, perhaps using onDeinit, but I don't know how.

Here's the relevant parts of my code: (I have removed the irrelevant parts for simplicity and readability. The removed parts have nothing to do with allocating or de-allocating memory)

in TimeManager.mqh:

CHashMap<string,CDynamicArray*> sessions;

bool fetchTradeTimes(string &symbols[], int numSymbols) {

    for (int i = 0; i < numSymbols; i++) {
        CDynamicArray *sessionsForSymbol = new CDynamicArray; // creating the pointer here and allocating space

        while (sessionExists) {
            // do stuff
            if (!sessionExists) {
                break;
            }
            sessionsForSymbol.AddValue((ulong)from); // adding values to CDynamicArray
            sessionsForSymbol.AddValue((ulong)to);
            sessionIndex++;
        }
        
        if (!sessions.Add(symbols[i],sessionsForSymbol)) { // adding the CDynamicArray to the HashMap at the given key position
            delete sessionsForSymbol; // delete the allocated space
            return false;
        }
        delete sessionsForSymbol; // delete the allocated space
    }
    debug_print_sessions(symbols,numSymbols);

    return true;
}

void debug_print_sessions(string &symbols[], int numSymbols) {
    for (int i = 0; i < numSymbols; i++) {
        CDynamicArray *sessionsForSymbol = new CDynamicArray; // allocating space
        sessions.TryGetValue(symbols[i],sessionsForSymbol);
        for (int j = 0; j < sessionsForSymbol.Size(); j+=2) {
                // do stuff            
        }
        delete sessionsForSymbol; // deleting space
    }
}

bool isTradeAllowedForSymbols(string &symbols[], int numSymbols, int numMinutes = 30) {

    for (int i = 0; i < numSymbols; i++) {
        CDynamicArray *sessionsForSymbol = new CDynamicArray;
        sessions.TryGetValue(symbols[i],sessionsForSymbol);
        

        string symbol = symbols[i];
        for (int j = 0; j < sessionsForSymbol.Size(); j+=2) {
            // do stuff
        }
        delete sessionsForSymbol;
        if (isAllowedForSymbol == false) return false;
    }
    return true;
}


and in Test.mq5

int OnInit()
  {
    string symbols[] = {"EURUSD","EURGBP","GBPUSD"};
    fetchTradeTimes(symbols,3);
    Print(isTradeAllowedForSymbols(symbols,3,30));
    return(INIT_SUCCEEDED);
  }

void OnDeinit(const int reason)
  {
   
  }

Any help is highly appreciated.

Thanks

 
bool fetchTradeTimes(string &symbols[], int numSymbols) {

    for (int i = 0; i < numSymbols; i++) {
        CDynamicArray *sessionsForSymbol = new CDynamicArray; // creating the pointer here and allocating space

        while (sessionExists) {
            // do stuff
            if (!sessionExists) {
                delete sessionsForSymbol;
                break;
            }
            sessionsForSymbol.AddValue((ulong)from); // adding values to CDynamicArray
            sessionsForSymbol.AddValue((ulong)to);
            sessionIndex++;
        }
        
        if (!sessions.Add(symbols[i],sessionsForSymbol)) { // adding the CDynamicArray to the HashMap at the given key position
            delete sessionsForSymbol; // delete the allocated space
            return false;
        }
        delete sessionsForSymbol; // delete the allocated space
    }
    debug_print_sessions(symbols,numSymbols);

    return true;
}
There should probably be another delete in the highlighted part.
 
Ernst Van Der Merwe:
There should probably be another delete in the highlighted part.

Thanks for the response. Could you elaborate please? What other delete?

 
afshin_j: Could you elaborate please? What other delete?

Do you really expect an answer? There are no mind readers here and our crystal balls are cracked. Always post all relevant code (using Code button).
     How To Ask Questions The Smart Way. 2004
          Be precise and informative about your problem

We can't see your broken code.

Fix your broken code.

 
William Roeder:

Always post all relevant code (using Code button).
     How To Ask Questions The Smart Way. 2004
          Be precise and informative about your problem

We can't see your broken code.

Fix your broken code.

Did you even read my post ? I have posted all relevant code, using Code button. Maybe you should learn reading posts carefully and completely, before trying to teach others how to post. As I mentioned before, the deleted parts have nothing to do with allocating/de-allocating memory, but here's the full code in case you're curious.

Test.mq5

#include <TimeManager.mqh>

int OnInit()
  {
    string symbols[] = {"EURUSD","EURGBP","GBPUSD"};
    fetchTradeTimes(symbols,3);
    Print(isTradeAllowedForSymbols(symbols,3,30));
    return(INIT_SUCCEEDED);
  }

void OnDeinit(const int reason)
  {
   
  }

TimeManager.mqh

#include <Generic\HashMap.mqh>
#include <cdynamicarray.mqh>

#define MAX_SESSIONS_PER_DAY 20

CHashMap<string,CDynamicArray*> sessions;
MqlDateTime currentTimeStruct;
datetime currentDateTime;

bool fetchTradeTimes(string &symbols[], int numSymbols) {
    TimeTradeServer(currentTimeStruct);

    for (int i = 0; i < numSymbols; i++) {
        bool sessionExists = true;
        int sessionIndex = 0;
        datetime from, to;

        CDynamicArray *sessionsForSymbol = new CDynamicArray;
        
        while (sessionExists) {
            sessionExists = SymbolInfoSessionTrade(symbols[i],(ENUM_DAY_OF_WEEK) currentTimeStruct.day_of_week,sessionIndex,from,to);
            if (!sessionExists) {
                break;
            }
            sessionsForSymbol.AddValue((ulong)from);
            sessionsForSymbol.AddValue((ulong)to);
            sessionIndex++;
        }


        if (!sessions.Add(symbols[i],sessionsForSymbol)) {
            PrintFormat("ERROR: Unable to add sessions to HashMap for symbol %s",symbols[i]);
            return false;
        }
    }
    debug_print_sessions(symbols,numSymbols);
    return true;
}


void debug_print_sessions(string &symbols[], int numSymbols) {
    for (int i = 0; i < numSymbols; i++) {
        CDynamicArray *sessionsForSymbol = new CDynamicArray;
        sessions.TryGetValue(symbols[i],sessionsForSymbol);
        for (int j = 0; j < sessionsForSymbol.Size(); j+=2) {
            Print("symbol ",symbols[i]," session ",j/2 + 1," from ",(datetime) sessionsForSymbol.Element[j], " to ",(datetime)sessionsForSymbol.Element[j+1]);
        }
    }
}


bool isTradeAllowedForSymbols(string &symbols[], int numSymbols, int numMinutes = 30, datetime spoofCurrentTime = -1) {
    int secondsInADay = 60 * 60 * 24;
    if (spoofCurrentTime == -1)
        currentDateTime = TimeTradeServer(currentTimeStruct);
    else {
        currentDateTime = spoofCurrentTime;
        TimeToStruct(currentDateTime,currentTimeStruct);
    }
    ulong secondsSinceStartDay = currentDateTime % secondsInADay;

    ENUM_DAY_OF_WEEK dayOfWeek = (ENUM_DAY_OF_WEEK) currentTimeStruct.day_of_week;
    if (dayOfWeek == SATURDAY || dayOfWeek == SUNDAY) return false;
    int seconds = numMinutes * 60;
    for (int i = 0; i < numSymbols; i++) {
        CDynamicArray *sessionsForSymbol = new CDynamicArray;
        sessions.TryGetValue(symbols[i],sessionsForSymbol);
        bool isAllowedForSymbol = false;

        string symbol = symbols[i];
        int size = sessionsForSymbol.Size();
        for (int j = 0; j < size ; j+=2) {
            ulong windowAfterOpen = sessionsForSymbol.Element[j] + seconds;
            ulong windowBeforeClose = sessionsForSymbol.Element[j+1] - seconds;
            datetime openWindow = (datetime) windowAfterOpen;
            datetime closeWindow = (datetime) windowBeforeClose;
            if (secondsSinceStartDay > windowAfterOpen && secondsSinceStartDay < windowBeforeClose ) {
                isAllowedForSymbol = true;
                break;
            }

        }
        if (isAllowedForSymbol == false) return false;
    }
    return true;
}
 
afshin_j:

Thanks for the response. Could you elaborate please? What other delete?

    for (int i = 0; i < numSymbols; i++) {
        CDynamicArray *sessionsForSymbol = new CDynamicArray; // creating the pointer here and allocating space

        while (sessionExists) {
            // do stuff
            if (!sessionExists) {  //if this expression is true, it exits the loop without deleting the object as delete is inside the loop.
                break;
            }
            sessionsForSymbol.AddValue((ulong)from); // adding values to CDynamicArray
            sessionsForSymbol.AddValue((ulong)to);
            sessionIndex++;
        }
        
        if (!sessions.Add(symbols[i],sessionsForSymbol)) { // adding the CDynamicArray to the HashMap at the given key position
            delete sessionsForSymbol; // delete the allocated space
            return false;
        }
        delete sessionsForSymbol; // delete the allocated space
    }
    debug_print_sessions(symbols,numSymbols);

    return true;
}
 
afshin_j:

Did you even read my post ? I have posted all relevant code, using Code button. Maybe you should learn reading posts carefully and completely, before trying to teach others how to post. As I mentioned before, the deleted parts have nothing to do with allocating/de-allocating memory, but here's the full code in case you're curious.

Test.mq5

TimeManager.mqh

There is no "delete" in this code.
 
afshin_j: Did you even read my post ? I have posted all relevant code, using Code button. Maybe you should learn reading posts carefully and completely, before trying to teach others how to post. As I mentioned before, the deleted parts have nothing to do with allocating/de-allocating memory, but here's the full code in case you're curious.
  1. Yes I did read your post completely.
  2. Your original post newed sessionsForSymbol and deleted it. Your problem was elsewhere.
  3. Post #4 has no deletes as Alain has already pointed out.
  4. Allocating/deallocating memory is the only way to generate your error.
  5. Being rude to people trying to help you is counterproductive.