Generic Class Library - bugs, description, questions, usage and suggestions - page 26

 
Andrey Pogoreltsev:

You create copies of objects in AddValue via new, but you don't release them in the destructor, you just clear the list of pointers.

help says that when you call a destructor, the destructors of the classes you used will also be called

https://www.mql5.com/ru/docs/standardlibrary/datastructures/carrayobj#carrayobjfeatures

I don't remember a case when the terminal didn't write into the log a warning about undestroyed objects after the script was unloaded - my example doesn't show such a warning


Andrey Pogoreltsev:

Secondly, you should have done it correctly with copy constructor instead of assignment operator. But this all is IMHO)

I've found information from developers that simple structures or classes in MQL are always copied without problems, I've checked it several times and it seems to be true, until I use the language features


This is what the discussion is about - MQL is not C++, I've stopped looking for analogies between them, the developers wrote that this is how it's implemented - I checked it, it works - so you can use it, if the standard C++ syntax is crucial, you can easily write all the logic in .dll

Документация по MQL5: Стандартная библиотека / Коллекции данных / CArrayObj
Документация по MQL5: Стандартная библиотека / Коллекции данных / CArrayObj
  • www.mql5.com
Класс CArrayObj обеспечивает возможность работы с динамическим массивом указателей на экземпляры класса CObject и его наследников. Это дает возможность работы как с многомерными динамическими массивами примитивных типов данных, так и с более сложно организованными структурами данных. В классе реализованы возможности добавления/вставки/удаления...
 
Andrey Pogoreltsev:

You create copies of objects in AddValue via new, but you don't free them in the destructor, you just clear the pointer list.

Oh, dear! And how can you delete an instance of a class created via new in the destructor. Try to do it. It will not work.

You can do it only in the destructor of some other class.

 
Nikolai Semko:

Oh, shit! And how can you delete an instance of a class created via new in the destructor. You may try it. It will not work.

You can do it only in the destructor of another class.

I was talking about the destructor of another class. I was speaking about items created through new in theAddValue method

 
Igor Makanu:

help says that when the destructor is called, the destructors of the classes used will also be called

https://www.mql5.com/ru/docs/standardlibrary/datastructures/carrayobj#carrayobjfeatures

i don't remember a case when the terminal didn't write a warning about undestroyed objects into the log after the script was unloaded - my example doesn't show such a warning


i heard from the developers that simple structures or classes in MQL are always copied without any problems, i checked it several times and it seems to be true, so far i use the possibilities of the language


This is what the discussion is about - MQL is not C++, I've stopped looking for analogies between them, the developers wrote that this is how it's implemented - I checked it, it works - so you can use it, if standard C++ syntax is crucial, I should not have to worry about putting all the logic into .dll.

Yes, I saw it in the help... Very implicit thing, looks more like a crutch, instead of unique_ptr...

 
Andrey Pogoreltsev:

Yes I saw it in the help... Very implicit thing, more like a crutch instead of unique_ptr...

And it's so handy that I can't even call it a crutch:

Create an object of any class, put it in a storage list, and you don't have to worry about removing it anymore - the terminal subsystem cleans it up by itself.
But you can also set manual operation and "run" for all newly created objects trying to track when, where and for what purposes it was created and whether it is needed now. If it is not needed, delete it. But when you made a mistake, it turns out it was needed - it crashes when accessing an invalid pointer...

So the crutch is just "chasing objects" looking for their uselessness and worrying about memory leaks if some object hasn't been caught up.

 
Andrey Pogoreltsev:

Secondly, the correct way to do it is through copy constructor, not assignment operator. But this is all IMHO)

Can you give me an example of how to copy it correctly for this template?

template<typename T>class CDataBase
  {
private:
   CList            *mlist;
   T                *Tptr;
public:
   void CDataBase()           { mlist=new CList;                                       }
   void ~CDataBase(void)      { delete mlist;                                          }
   int ArraySize(void)        { return(mlist.Total());                                 }
   T *operator[](int index)   { return(mlist.GetNodeAtIndex(index));                   }
   void  AddValue (T &value)  { Tptr = new T; Tptr  = value; mlist.Add(Tptr);          }
   string TypeName()          { return(typename(T));                                   }
  };

I used help to write AddValue methodhttps://www.mql5.com/ru/docs/basis/types/classes

I racked my brains, but I don't see any other solution in MQL than the one I wrote in my example!

Show me your implementation of correct data storage

Документация по MQL5: Основы языка / Типы данных / Структуры, классы и интерфейсы
Документация по MQL5: Основы языка / Типы данных / Структуры, классы и интерфейсы
  • www.mql5.com
Структура является набором элементов произвольного типа (кроме типа void). Таким образом, структура объединяет логически связанные данные разных типов. Объявление структуры Имя структуры нельзя использовать в качестве идентификатора (имени переменной или функции). Следует иметь ввиду, что в MQL5 элементы структуры следуют непосредственно друг...
 
Artyom Trishkin:

And it's so handy that you can't even call it a crutch:

Create any object of any class, put it into storage list, and you don't have to worry about removing it anymore - terminal subsystem cleans it up by itself.
But you can also set manual operation and "run" for all the newly created objects trying to find out when, where and for what purposes it was created and whether it is needed now. If it is not needed, delete it. But when you made a mistake, it turns out it was needed - it crashes when accessing an invalid pointer...

So the crutch is just "chasing objects" looking for their uselessness and worrying about memory leaks if some object hasn't been caught up.

What I mean here is that when you add a pointer to the collection, it stays with you as well. This is the first thing.

Second, we're not talking about arrays-collections and continuous reading; you have a fragmented system.

Third, you can't guarantee that you've passed a pointer to a collection object.
 
Andrey Pogoreltsev:
The point here is that once you add a pointer to the collection, it also stays with you. That's the first thing.

Second, we are not talking about arrays-collections and continuous reading; you have a fragmented system.

Third, no one guarantees that you passed a pointer to the collection object.
  1. I meant that automatic removal by the terminal subsystem of all your created objects and put pointers to them in lists you call a crutch, and you don't consider manual manipulation of your objects and creating crutches for it a crutch.
  2. That wasn't part of what you said in item 1, and is the main reason I responded.
  3. That too, and for the same reason.
 
Igor Makanu:

help says that when the destructor is called, the destructors of the classes used will also be called

https://www.mql5.com/ru/docs/standardlibrary/datastructures/carrayobj#carrayobjfeatures

i don't remember a case when the terminal didn't write a warning about undestroyed objects into the log after the script was unloaded - my example doesn't show such a warning


i heard from the developers that simple structures or classes in MQL are always copied without any problems, i checked it several times and it seems to be true, so far i use the possibilities of the language


This is what the discussion is about - MQL is not C++, I've given up looking for analogies between them, the developers wrote that this is how it is implemented - I checked it, it works - so you can use it, if the standard C++ syntax is crucial, you can easily write all the logic in .dll

Can a triangular array be made with this?

 

Due to language limitations, it's unlikely that anything decent will work. I have this crutch (a lightweight wrapper over a standard array).

#define  GENERATE_VECTOR_GROWTH_FACTOR 2
#define  GENERATE_VECTOR(NAME, REF)                                         \  
   template <typename T>                                                   \
   class NAME                                                              \
   {                                                                       \
      int sz;                                                              \
      bool fail_state;                                                     \
   public:                                                                 \
      T a[];                                                               \
      NAME(): sz(0), fail_state(false) {}                                  \
      bool operator!()const      {return this.fail_state;}                 \
      uint size()const           {return this.sz;}                         \
      void clear()               {this.sz = 0; this.fail_state = false;}   \
      void push_back(T REF value) {                                        \
         if (this.sz == ArraySize(this.a)  &&                              \
             ArrayResize(this.a, this.sz*                                  \
                           GENERATE_VECTOR_GROWTH_FACTOR+1) == -1) {       \
            this.fail_state = true;                                        \
            return;                                                        \
         }                                                                 \
         this.a[this.sz++] = value;                                        \
      }                                                                    \
      void reserve(int new_cap) {                                          \
         if (new_cap > ArraySize(this.a))                                  \
            ArrayResize(this.a, new_cap);                                  \
      }                                                                    \
      void erase(int pos) {                                                \
         if ( ! ArrayRemove(this.a, pos, 1) )                              \
            this.fail_state = true;                                        \
      }                                                                    \
   };
#define  GENERATE_VECTOR_EMPTY
GENERATE_VECTOR(vector_fund, GENERATE_VECTOR_EMPTY);  // для фундаментальных типов
GENERATE_VECTOR(vector_ref, const &);                 // для пользовательских
#undef  GENERATE_VECTOR_EMPTY
#undef  GENERATE_VECTOR_GROWTH_FACTOR

struct S {int a;};
class Q {};
bool f() {
   vector_ref<S> v1;
   vector_fund<int> v2;
   vector_ref<Q> v3;
   
   Q q;
   v3.push_back(q);
   v2.push_back(3);
   v2.a[0] = 5;
   
   return !(!v1 || !v2 || !v3);
}

To store pointers, write a unic_ptr wrapper (although you can't get a full-fledged one, but auto_ptr at least). In my opinion, even such a primitive is much more convenient than std's template counterparts.

Reason: