Libraries: CDictionary class - page 2

 

I've discovered a bug in CDictionary. When you use the Reset Method it deletes the CList object in m_data. Subsequent calls to other methods that fetch the point from the dictionary receive a bad pointer in return. Example:


#include "Dictionary.mqh"

void OnStart()
{
   CDictionary d;
   d.Set("key", 1);
   d.Reset();
   Print(d.Contains<int>("key"));
}


I would propose the following fix for all methods which use the key hash to access a CList object from the m_data array. 


template<typename T>
bool CDictionary::Contains(string key)
  {
   bool res=false;
   T value=NULL;
   int index=Index(Hash(key+typename(T)));
   if(CheckPointer(m_data[index]) == POINTER_INVALID)
      m_data[index] = new CList;
   CList *list=m_data[index];
   if(CheckPointer(list))
     {
      CDictionaryEntryBase *model=new CDictionaryEntry<T>(key,value);
      if(CheckPointer(list.Search(model)))
         res=true;
      delete model;
     }
   return res;
  }
 
nicholi shen:

I've discovered a bug in CDictionary. When you use the Reset Method it deletes the CList object in m_data. Subsequent calls to other methods that fetch the point from the dictionary receive a bad pointer in return. Example:



I would propose the following fix for all methods which use the key hash to access a CList object from the m_data array. 


Thanks nicoli shen. Your solution is the 'safer' one. However, I cannot reproduce the issue.

Another thing that bothers me related to this: an object pointer should be able to accept a null value. m_data is a dynamic array, so it should return null when an unfilled index from the array is retrieved, or the item stored is deleted. Storing data from m_data to CList* without checking the pointer beforehand is also done on other methods like Get() and Delete(), so the test scripts above should also fail if this issue exists. A simple assignment between one pointer and another can be done without any pointer access errors, even if the object the lvalue points to is already deleted:

#include <Object.mqh>
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   CObject *obj = new CObject();
   delete obj;
   CObject *obj1 = obj; //no invalid pointer access errors
  }
//+------------------------------------------------------------------+

The issue can be reduced to the example above. But in this case, there are no pointer errors. I am curious because I remember encountering this same problem in an earlier build, which was quickly patched.

I am currently using MT5 build 1932, but let me know if I am missing something.

[Deleted]  

I have these error:


'Key' - unexpected token, probably type is missing? Dictionary.mqh 39 23

'Key' - function already defined and has different type Dictionary.mqh 39 23

   see declaration of 'CDictionaryEntryBase::Key' Dictionary.mqh 20 22



trying to complie on build 3320

 
Sunfire #:

I have these error:


'Key' - unexpected token, probably type is missing? Dictionary.mqh 39 23

'Key' - function already defined and has different type Dictionary.mqh 39 23

   see declaration of 'CDictionaryEntryBase::Key' Dictionary.mqh 20 22



trying to complie on build 3320

Try putting the keyword "void" before the class method
 
This code demonstrates excellent functionality and leverages CObject inheritance, enabling seamless integration with CArray structures within the dictionary.
 
For adding a integer array to the dictionary:
#include "Include\Dictionary.mqh"
#include <Arrays\ArrayInt.mqh>
/

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit()
  {
//---

   CDictionary my_dict;
   
   //--- add arrayint to dictionary
   CArrayInt *my_arr_int= new CArrayInt;
   my_arr_int.Add(10);
   my_arr_int.Add(30);
   my_arr_int.Add(45);
   my_dict.Set<CObject*>("arrayint", my_arr_int);
   
   CArrayInt *res_arr;
   res_arr= my_dict.Get<CObject*>("arrayint");
   Print("intarray at 1= ",res_arr.At(1));
//---
   return(INIT_SUCCEEDED);
  }