Invalid Pointer Access - Distilled ...

 

My earlier similar titled post refers. I've distilled the issue down to the following:-


bool CPivotManager::_getPendingHighBefore(datetime priorToTime,datetime &timeFound)
  {

   int total=_highPivots.Total();
   bool result=false;
   CObjVector<CPivotCandidate>*sortPivotCandidates=new CObjVector<CPivotCandidate>();

   for(int i=0;i<total;i++)
     {

      if(_highPivots[i].GetIgnore()) continue;

      if(_highPivots[i].GetPivotTime()<priorToTime)
        {

         // Get copy
         CPivotCandidate sortCandidate=_highPivots[i];
         sortPivotCandidates.Add(GetPointer(sortCandidate));

        }

     }

   if(sortPivotCandidates.Total()>0)
     {

      sortPivotCandidates.Sort(PM_SORT_ASCENDING);
      timeFound=sortPivotCandidates[0].GetPivotTime(); // <-- Invalid Pointer Access
      result=true;

     }

   return result;

}

I create the sortPivotCandidates object in the method. At the first hit, there is exactly 1 item in _highPivots. I create a copy of that object and then get its pointer and add it to the sortPivotCandidates collection. The collection is sorted and then I try to reference the object at position 0 (zero). When I do this, I get an "Invalid Pointer Access" message. I can't see what I am doing wrong here. If anyone can enlighten me, I'd appreciate it.

 

Geester:

When I do this, I get an "Invalid Pointer Access" message. I can't see what I am doing wrong here. If anyone can enlighten me, I'd appreciate it.

I am unfamiliar with the specifics of CObjVector, so I am proffering a guess.

Often when you want to access an item in a dynamic array, you use something like the .At() method to access a specific index.

For example, in CArrayDouble you would access the 0'th item using:

https://www.mql5.com/en/docs/standardlibrary/datastructures/carraydouble/carraydoubleat

 

It looks like you're getting mixed up on when/how to use pointers and statically allocated objects... Try this.

bool CPivotManager::_getPendingHighBefore(datetime priorToTime,datetime &timeFound)
{
   bool result=false;
   CObjVector<CPivotCandidate> sortPivotCandidates;
   int total=_highPivots.Total();
   for(int i=0;i<total;i++)
   {
      if(_highPivots[i].GetIgnore()) 
         continue;

      if(_highPivots[i].GetPivotTime()<priorToTime)
         sortPivotCandidates.Add(_highPivots[i]);
   }
   if(sortPivotCandidates.Total()>0 && sortPivotCandidates[0]!=NULL)
   {
      sortPivotCandidates.Sort(PM_SORT_ASCENDING);
      timeFound=sortPivotCandidates[0].GetPivotTime(); // <-- Invalid Pointer Access
      result=true;
   }
   return result;
}

 Also, I would use this version of object vector in order to avoid confusion since the vector is holding pointers not the objects themselves.

#include <Arrays\ArrayObj.mqh>
template<typename T>
class objvector : public CArrayObj
{
public:
   T operator[](const int index) const { return At(index); }
};
objvector<CObject*> my_vect;
 

It just dawned on my that I forgot an import step in the code... CArrayObject has automatic memory management and will automatically delete the dynamic objects to which it points unless it is explicitly turned off. Here are some of my notes on how it works. 

class Num : public CObject
{
   public: int num;
};

void OnStart()
{
//---
   Num num; //static class instance, automatically gets destroyed when scope runs out
   Num *num_ptr; //nullptr
   num_ptr = new Num; // dynamic object only gets detroyed when using delete
   delete num_ptr; // remember to always detroy dynamic objects or suffer memory leaks
   
   CArrayObj array; //static class instance. IMPORTANT this class has automatic memory management and will delete all dynamic objects unless turned off.
   array.Add(new Num); //dynamic object stored in pointer array and gets deleted automatically when the CArrayObj class runs out of scope.
   
   { // inner scope
      CArrayObj array_short_scope;
      array_short_scope.AssignArray(&array);
   }
   Print("array size = ",array.Total());
   //Array size is still 1, but the object to which it is pointing has been destroyed. This will throw a bug when trying to access the object in array!
   array.Clear();
   
   array.Add(new Num);
   
   { //inner scope
      CArrayObj temp_list;
      temp_list.FreeMode(false); 
      temp_list.AssignArray(&array);  
   }
   Print(array.Total()," num= ",((Num*)array.At(0)).num);
}
//+------------------------------------------------------------------+

Additionally when using the Collection classes, it's best to not assign it pointers to static objects (which I see you do a lot) because you run the risk of a static object running out of scope leaving a null pointer in the collection. 

   CArrayObj array;
   Num n1; 
   array.Add(&n1); //This should rarely need to be the case...only if you really need to.
   
   Num *n2 = new Num;
   array.Add(n2); //No risk of n2's dynamic object detroying from scope

In other words control the dynamic object memory management by controlling the scope of the static collection class. This is the proper way to implement the temporary collection... 

#include <Arrays\ArrayObj.mqh>
template<typename T>
class objvector : public CArrayObj
{
public:
   T operator[](const int index) const { return At(index); }
};

bool _getPendingHighBefore(datetime priorToTime,datetime &timeFound)
{
   objvector<CPivotCandidate*> temp_list;
   temp_list.FreeMode(false);
   int total=_highPivots.Total();
   for(int i=0;i<total;i++)
   {
      if(_highPivots[i].GetIgnore()) 
         continue;

      if(_highPivots[i].GetPivotTime()<priorToTime)
         temp_list.Add(_highPivots[i]);
   }
   if(sortPivotCandidates.Total()>0 && sortPivotCandidates[0]!=NULL)
   {
      sortPivotCandidates.Sort(PM_SORT_ASCENDING);
      timeFound=sortPivotCandidates[0].GetPivotTime(); // <-- Invalid Pointer Access
      return true;
   }
   return false;
}

This doesn't appear to need a temporary collection and could get a huge efficiency boost by doing something like this. 

bool _getPendingHighBefore(datetime priorToTime,datetime &timeFound)
{
   datetime recent_time = 0;
   for(int i=_highPivots.Total()-1;i>=0;i--)
   {
      if(_highPivots[i].GetIgnore()) 
         continue;
      datetime gp_time = _highPivots[i].GetPivotTime();
      if(gp_time < priorToTime && gp_time > recent_time)
         recent_time=gp_time;
   }
   if(recent_time > 0)
   {
      timeFound=recent_time;
      return true;
   }
   return false;
}
 
Anthony Garot:

I am unfamiliar with the specifics of CObjVector, so I am proffering a guess.

Often when you want to access an item in a dynamic array, you use something like the .At() method to access a specific index.

For example, in CArrayDouble you would access the 0'th item using:

https://www.mql5.com/en/docs/standardlibrary/datastructures/carraydouble/carraydoubleat


Hello @Anthony Garot - many thanks indeed for the link to At! It's fair to say that I tend to use approaches I am more familiar with from higher level languages like PHP/Javascript but I should use what's on offer from MQL. I really appreciate the heads-up :)

Cheers,

--G

 
nicholishen:

It just dawned on my that I forgot an import step in the code... CArrayObject has automatic memory management and will automatically delete the dynamic objects to which it points unless it is explicitly turned off. Here are some of my notes on how it works. 

Additionally when using the Collection classes, it's best to not assign it pointers to static objects (which I see you do a lot) because you run the risk of a static object running out of scope leaving a null pointer in the collection. 

In other words control the dynamic object memory management by controlling the scope of the static collection class. This is the proper way to implement the temporary collection... 

This doesn't appear to need a temporary collection and could get a huge efficiency boost by doing something like this. 


Hey, @nicholishen, OMG, thank you so much for your brilliant reply and code samples! Every time, I read something from you, a light bulb switches on! :) You are correct, I didn't really acknowledge that something like: "Num num;" is a static class instance. I read the documentation and I got the impression that this was a way of new'ing up an object but not having to handle deleting it later. I also hadn't taken on board the "objvector<CPivotCandidate*> tempList;" where you have included the "*" in the angle brackets. Moreover, I don't think I appreciated that an object pointer is therefore cast to the object type it is pointing to. Not being familiar with pointers, I just thought a pointer was, well, a pointer! :)

Your replies have been like a little "master class" for me and I can't tell you how much I appreciate your help!!

Thank you very much.

Cheers,

--G


 
Geester:

Hey, @nicholishen, OMG, thank you so much for your brilliant reply and code samples! Every time, I read something from you, a light bulb switches on! :) You are correct, I didn't really acknowledge that something like: "Num num;" is a static class instance. I read the documentation and I got the impression that this was a way of new'ing up an object but not having to handle deleting it later. I also hadn't taken on board the "objvector<CPivotCandidate*> tempList;" where you have included the "*" in the angle brackets. Moreover, I don't think I appreciated that an object pointer is therefore cast to the object type it is pointing to. Not being familiar with pointers, I just thought a pointer was, well, a pointer! :)

Your replies have been like a little "master class" for me and I can't tell you how much I appreciate your help!!

Thank you very much.

Cheers,

--G



No worries, here's another good example of tying it all together. https://www.mql5.com/en/forum/221493#comment_6139960

Multi-Dimensional Array problem
Multi-Dimensional Array problem
  • 2017.12.01
  • www.mql5.com
hello everyone, I think this maybe an easy problem to solve, but I can't get it to work with out causing an error...
 
nicholishen:

No worries, here's another good example of tying it all together. https://www.mql5.com/en/forum/221493#comment_6139960


Thanks @nicholishen. All that templated stuff looks pretty hairy! I didn't realise you could define classes within other classes as per your two dimensional data code. Impressive stuff.


Cheers!

-G



 
Geester:

Thanks @nicholishen. All that templated stuff looks pretty hairy! I didn't realise you could define classes within other classes as per your two dimensional data code. Impressive stuff.


Cheers!

-G




Yeah, just know that for whatever reason MQL doesn't treat inner classes as private even though they may be defined as such. 

 
nicholish en #:
   

   Num num; //static class instance, automatically gets destroyed when scope runs out

just one correction:

by its nature it is NOT static, but it has automatic Storage Duration (being allocated in stack, not o heap) - & therefore being destroyed when goes out-of-scope... but static variables are being allocated in a special memory area, that is provided exactly for static variables & this memory area gets free after the finish of the whole program (even after OnDeinit)
Reason: