problem with wrapper class which encapsulates a generic container

 

I'm trying to use a wrapper class to encapsulate the functionality of mql5 generic container classes. But when I try to retrieve a value from the container via a method of the wrapper class the pointer gets invalid. The object in the container still exists and the pointer is still valid in the method as you can see in the debugger. But outside the function the pointer doesn*t exist anymore.
If I return the pointer directly, the problem doesn't occur. But I would like to handle any errors in the wrapper class and don*t want to check the result of CItem* (and raise errors, write logs, etc.) in my client code. And besides that I would have to rewrite some classes to work around the problem.
So I want to ask, if

- there is some problem in my code and I overlooked something (I don*t think so)
- it's an issue of the build
- or if there is some other workaround without changing the signature of the methods of the wrapper classes


My MT5-Build is 4150.

Here is my sample code. I put all classes together in one file, so it is easier to reproduce the problem:

#include <Generic\SortedMap.mqh>

class CItem{};

class CWrapper
{
   private:
      CSortedMap<string, CItem*>   m_Items;
   public:
      bool     AddItem  (string key, CItem* value);
      bool     GetItem  (string key, CItem* value);
      bool     GetItem2 (string key, CItem*& value);
      CItem*   GetItem  (string key);
};

bool CWrapper::AddItem  (string key, CItem* value)
{
   return m_Items.Add(key, value);
}

bool CWrapper::GetItem  (string key, CItem* value)
{
   return m_Items.TryGetValue(key, value);
}

bool CWrapper::GetItem2  (string key, CItem*& value)
{
   return m_Items.TryGetValue(key, value);
}

CItem* CWrapper::GetItem  (string key)
{
   CItem* Value;
   m_Items.TryGetValue(key, Value);
   return Value;
}

CWrapper Wrapper;

int OnInit()
{
   CItem* AddItem = new CItem();
   bool success = Wrapper.AddItem("I1", AddItem);
   
   CItem* ResItem1;
   success = Wrapper.GetItem("I1", ResItem1);
   
   CItem* ResItem2;
   success = Wrapper.GetItem("I1", ResItem2);
   
   CItem* ResItem3 = Wrapper.GetItem("I1");
   
   Print("AddItem:", EnumToString(CheckPointer(AddItem)));
   Print("ResItem1:", EnumToString(CheckPointer(ResItem1))); 
   Print("ResItem2:", EnumToString(CheckPointer(ResItem2)));
   Print("ResItem3:", EnumToString(CheckPointer(ResItem3)));     
   return(INIT_SUCCEEDED);
}
 
Sascha Thomas:

I'm trying to use a wrapper class to encapsulate the functionality of mql5 generic container classes. But when I try to retrieve a value from the container via a method of the wrapper class the pointer gets invalid. The object in the container still exists and the pointer is still valid in the method as you can see in the debugger. But outside the function the pointer doesn*t exist anymore.
If I return the pointer directly, the problem doesn't occur. But I would like to handle any errors in the wrapper class and don*t want to check the result of CItem* (and raise errors, write logs, etc.) in my client code. And besides that I would have to rewrite some classes to work around the problem.
So I want to ask, if

- there is some problem in my code and I overlooked something (I don*t think so)
- it's an issue of the build
- or if there is some other workaround without changing the signature of the methods of the wrapper classes


My MT5-Build is 4150.

Here is my sample code. I put all classes together in one file, so it is easier to reproduce the problem:

This signature is actually corrupting your object:

bool CWrapper::GetItem  (string key, CItem* value)


EDIT:

Reason is, you are storing pointers, and you are passing in a pointer, but the value cannot be sent back to you, because you are using a pointer. You should be using the signature from GetItem2 function. - A reference to a pointer, so that you actually get back the value, you are looking for.

The function:

CItem* CWrapper::GetItem  (string key)

Is woring as expected, and actually gives you the object pointer back.

 

Thank you

The GetItem2-Function is the way I would do it in standard C++, but it is not working in MQL5. It is not surprising because according to documentation only references to value-types, structs and arrays are supported. Yesterday I thought it had compiled but I forgot to call the function GetItem2 in code.
So the only way to get back a pointer to a class object from a function is like this:

CItem* CWrapper::GetItem  (string key);

or?

Do you know, why references to pointers are working in templates but not in classes? (In the TryGetValue-Functions of the generic classes it is used and obviously working)

 
Sascha Thomas #:

Thank you

The GetItem2-Function is the way I would do it in standard C++, but it is not working in MQL5. It is not surprising because according to documentation only references to value-types, structs and arrays are supported. Yesterday I thought it had compiled but I forgot to call the function GetItem2 in code.
So the only way to get back a pointer to a class object from a function is like this:


or?

Do you know, why references to pointers are working in templates but not in classes? (In the TryGetValue-Functions of the generic classes it is used and obviously working)

Passing in a pointer on a reference should be possible, at least it was in earlier builds, if that's not the case anymore, then I would guess it's maybe a bug, and has been introduced recently.

I don't have the time to investigate on this, would be nice if you could verify that on your side. I am willing to follow and verify your findings.

EDIT:
Also try to see if turning off optimized builds helps...
 

Sorry, I made a mistake.

bool     GetItem2 (string key, CItem*& value);
works and I get a valid pointer. Thank you very much for your help.
 
Sascha Thomas #:

Sorry, I made a mistake.

works and I get a valid pointer. Thank you very much for your help.
Good. - Solved....

Reason: