Templated library crashes MT4 editor

Hello,

This is the first time that I’ve used the keyword template so I’m not sure I’m using it correctly.

I’ve modified Konstantin Gruzdev’s CArrayRing buffer found here: https://www.mql5.com/en/code/1340 to allow any type to be added to the buffer. However,

when i use it, the MT4 editor crashes violently.

The code that I type is this:

CArrayRing *buffer;

buffer = new CArrayRing();

buffer.Init 

and it is exactly when I enter the ( of the Init method the editor crashes.

What am I doing wrong?

Here’s my modified code:

//+------------------------------------------------------------------+
//|                                                   CArrayRing.mqh |
//|                               Copyright 2012, Konstantin Gruzdev |
//|                            https://login.mql5.com/ru/users/Lizar |
//|                                             Revision 03 Dec 2012 |
//+------------------------------------------------------------------+
#property copyright   "Copyright 2012, Konstantin Gruzdev"
#property link        "https://login.mql5.com/ru/users/Lizar"

//+------------------------------------------------------------------+
//| Class CArrayRing                                                 |
//| Appointment: class is designed to work with tne finite ring      |
//|    buffers of data. When the buffer is crowded the oldest        |
//|    buffer element is replaced by the newest element. Herewith,   |
//|    the specified number of end elements are always available.    |
//| Link: http://www.mql5.com/ru/code/1340                           |
//| Remark: it should also be kept in mind that the element indexing |
//|    in the ring buffer is executed as in timeseries.              |
//+------------------------------------------------------------------+

class CArrayRing
  { 
private:
template<typename T>  
   T                 m_data[];         // ring buffer of data
   int               m_size;           // buffer size
   int               m_last_pos;       // last buffer element position
   double            m_filling;        // value, which used for the array filling

public:
                     CArrayRing();
                    ~CArrayRing()                  { ArrayFree(m_data);                         }
   template<typename T>  
   //--- buffer initialization method:
   bool              Init(int size, T value=EMPTY_VALUE);             
   //--- method returns the buffer size:
   int               Size()                        { return m_size-1;                           }
   //--- method changes the ring buffer size:
   bool              Resize(const int size);
   template<typename T>  
   //--- method of adding a new element to the buffer:
   void              Add(const T element); 
   //--- method returns the value of element with the specified index:
   double            At(const int index) const;
   double operator   [](const int index) const     { return(At(index));                         }
   //--- method returns the value of the last element stored in the buffer:
   double            Last() const                  { return(m_data[m_last_pos]);                } 
   //--- method overwrites the value of the last element in the buffer:
   void              Last(const T element)    { m_data[m_last_pos]=element;                     } 
   template<typename T>   
   //--- method overwrites the value of element with the specified index:
   bool              Update(const T element,const int index=0);  
  };
//+------------------------------------------------------------------+
//| Constructor.                                                     |
//+------------------------------------------------------------------+
CArrayRing::CArrayRing() : m_last_pos(0),
                           m_filling(EMPTY_VALUE),
                           m_size(ArraySize(m_data))
  {
  }

//+------------------------------------------------------------------+
//| Buffer initialization method.                                    |
//+------------------------------------------------------------------+
template<typename T>  
bool CArrayRing::Init(int size, T value=EMPTY_VALUE)
  {
   m_last_pos=0;                          // last element position
   m_filling=value;                       // value for buffer filling
   m_size=ArraySize(m_data);              // get size of the buffer   
   bool result=Resize(size);              // create a buffer with the desired size
   ArrayFill(m_data,0,m_size,m_filling);  // fill the buffer with default values
   return(result);                  
  }  

//+------------------------------------------------------------------+
//| Set the new size of the array.                                   |
//+------------------------------------------------------------------+
bool CArrayRing::Resize(const int new_size)
  {
//--- check
   if(new_size<0) return(false);
//--- increase array size:
   if(new_size>m_size)
     {
      int set_size=ArrayResize(m_data,new_size);
      if(set_size<0) return(false);
      //--- copy elements to restore their order:
      if(set_size>m_size)
        {
         for(int i=m_size-1,j=set_size-1;i>m_last_pos;i--,j--)
           {
            m_data[j]=m_data[i];
            m_data[i]=m_filling;
           }
        }
      m_size=set_size;
      //--- result:
      return(true);      
     }
//--- reduce array size:
   //--- prepare array to reduce the size:
   if(new_size>m_last_pos+1)
      for(i=m_size-1,j=new_size-1;j>m_last_pos;i--,j--) m_data[j]=m_data[i];
   else
     {
      for(i=m_last_pos+1-new_size,j=0;i<=m_last_pos;i++,j++) m_data[j]=m_data[i];    
      m_last_pos=new_size-1;
     }
   //--- reduce the size:
   m_size=new_size;
   ArrayResize(m_data,new_size);
//--- result:
   return(true);
  }
  
//+------------------------------------------------------------------+
//| Adding a new element to the buffer.                              |
//+------------------------------------------------------------------+
template<typename T>  
void CArrayRing::Add(const T element)
  {
   m_last_pos=++m_last_pos%m_size;
   m_data[m_last_pos]=element;
  } 
  
//+------------------------------------------------------------------+
//| Gets the element at the specified index.                         |
//+------------------------------------------------------------------+
double CArrayRing::At(const int index) const
  {
//--- check the index correctness:
   if((index/m_size)==0) 
//--- return the value of element with the specified index:
      return(m_data[(m_size+m_last_pos-index)%m_size]);
//--- if the index is wrong:
   return(DBL_MAX);   
  }  

//+------------------------------------------------------------------+
//| Update the element at the specified position in the array.       |
//+------------------------------------------------------------------+
template<typename T>  
bool CArrayRing::Update(const T element,const int index=0)
  {
//--- check the index correctness:
   if((index/m_size)==0) 
     {
//--- update
      m_data[(m_size+m_last_pos-index)%m_size]=element;
//--- successful
      return(true);
     }
//--- if the index is wrong:
   return(false);   
  }

Your mqh file doesn’t compile.

If you want to report an issue, please provide ALL steps to reproduce it.

Which build are you using ?

I’ve reported the issue already. I need 1) know if the file is correct, 2) how to fix it if not.

I’ve attached the actual file I’m using although the one above compiled for me also.

I’m using MetaEditor v5.0 1601 19 May 2017

Thanks.

Files:

CArrayRing.mqh 7 kb

You need to templatize the class and not the individual elements/methods of the class. Here is a quick-and-dirty…

#include <carrayringT.mqh>
void OnStart()
{
   CArrayRing<int> ring;
   ring.Init(10);
   
   for(int i=100000; i>=0; --i)
      ring.Add(i);
   
   for(int i=ring.Size()-1; i>=0; --i)
      Print(ring[i]);
}

File: carrayringT.mqh 7 kb

I confirm it crashes with this build 1601. It doesn’t crash with ME build 1910.

Your mqh file compiles because it doesn’t use #property strict, if you use it (which is recommended) it doesn’t compile.

Thanks for your help.

That seems to work except when I try to create a type of a struct.

For instance:

struct S_BUFFER
{
   double s;
   double st;
   double p;
}

CArrayRing<S_BUFFER> *buffer;

Creates this error

'CArrayRing' - identifier already used  

Is this normal? Can I not use structure or class types? If I doing something wrong then what is it please.

Thanks in advance.

Thanks, worth knowing.

You have this compiling error because you need to add a ; at then of your struct declaration.

struct S_BUFFER
  {
   double            s;
   double            st;
   double            p;
  };

But you will have other compilation errors as a struct can’t always be used in place of a standard type.

Thanks.

You were too quick. I’ve just noticed that however, the error now is:

'S_BUFFER' - objects are passed by reference only

And I’m not sure how to adjust the code to do this tried adding a & to the Init volue value but that doesn’t seem to have any impact.

Thanks again!

Mql isn’t like c++ in those regards. Structs have to be passed by reference and cannot be converted to pointers. Classes can be pointers, but create all new dynamics for this sort of thing. If you want to use structs in this collection then you need to specialize this collection for stucts.

Unfortunately, there is not an easy way to have a template working with all possible types (standard, struct, objects, pointers).

Thanks for your reply. I’ll have a play.

Thanks for your reply.