Библиотека Generic классов - ошибки, описание, вопросы, особенности использования и предложения - страница 26

 
Andrey Pogoreltsev:

Вы создаете копии объектов в AddValue через new, но не освобождаете их в деструкторе, просто список указателей очищаете.

в справке написано, что при вызове деструктора будут также вызваны деструкторы классов которые использовались

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

не припомню случая, чтобы терминал после выгрузки скрипта не записал в лог предупреждение об не уничтоженных объектах - мой пример не выводит такое предупреждение


Andrey Pogoreltsev:

Во-вторых, по правильному нужно было через конструктор копирования сделать, а не оператор присваивания. Но это все ИМХО)

по сообщениям разработчиков я находил информацию, что простые структуры или классы в MQL копируются всегда и без проблем, несколько раз я проверял, вроде так и есть, пока пользуюсь возможностями языка


тут в общем к чему все обсуждение - MQL это не С++, я давно перестал искать аналогии между ними, написали разработчики что вот так реализовано - проверил, работает - значит можно использовать, если критично иметь стандартный С++ синтаксис, вынести всю логику в .dll не составляет труда

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

Вы создаете копии объектов в AddValue через new, но не освобождаете их в деструкторе, просто список указателей очищаете.

Во блин! А как можно в деструкторе удалить экземпляр класса, созданный через new. Попробуйте. Не получиться.

Можно это сделать только в деструкторе другого класса.

 
Nikolai Semko:

Во блин! А как можно в деструкторе удалить экземпляр класса, созданный через new. Попробуйте. Не получиться.

Можно это сделать только в деструкторе другого класса.

Речь и шла о деструкторе другого класса. Я говорил об элементах, созданных через new в методе AddValue 

 
Igor Makanu:

в справке написано, что при вызове деструктора будут также вызваны деструкторы классов которые использовались

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

не припомню случая, чтобы терминал после выгрузки скрипта не записал в лог предупреждение об не уничтоженных объектах - мой пример не выводит такое предупреждение


по сообщениям разработчиков я находил информацию, что простые структуры или классы в MQL копируются всегда и без проблем, несколько раз я проверял, вроде так и есть, пока пользуюсь возможностями языка


тут в общем к чему все обсуждение - MQL это не С++, я давно перестал искать аналогии между ними, написали разработчики что вот так реализовано - проверил, работает - значит можно использовать, если критично иметь стандартный С++ синтаксис, вынести всю логику в .dll не составляет труда

Да увидел в справке... Очень неявная штука, похожая больше на костыль, вместо unique_ptr...

 
Andrey Pogoreltsev:

Да увидел в справке... Очень неявная штука, похожая больше на костыль, вместо unique_ptr...

И настолько удобная, что и костылём назвать "рука не поднимается":

Создали объект любого класса, поместили его в список-хранилище, и больше не нужно заботиться о его удалении - подсистема терминала сама всё почистит.
Но можно и задать ручное управление, и "бегать" за всеми вновь создаваемыми объектами в попытках отследить когда, где и для каких нужд он был создан, и нужен ли он теперь. Не нужен - удалить. А ошибся - нужен оказывается был - вылетел по обращению к невалидному указателю...

Так что костыль - как раз "беготня за объектами" в поисках их ненадобности и переживании об утечках памяти в случае, ежли не догнал-таки какой-то из объектов.

 
Andrey Pogoreltsev:

Во-вторых, по правильному нужно было через конструктор копирования сделать, а не оператор присваивания. Но это все ИМХО)

как правильно копировать, пример можете привести для этого шаблона?

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));                                   }
  };

я пользовался справкой для написания метода AddValue https://www.mql5.com/ru/docs/basis/types/classes

всю голову сломал, но я не вижу в MQL другого решения чем я написал в своем примере!

Вашу реализацию правильного хранения данных покажите 

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

И настолько удобная, что и костылём назвать "рука не поднимается":

Создали объект любого класса, поместили его в список-хранилище, и больше не нужно заботиться о его удалении - подсистема терминала сама всё почистит.
Но можно и задать ручное управление, и "бегать" за всеми вновь создаваемыми объектами в попытках отследить когда, где и для каких нужд он был создан, и нужен ли он теперь. Не нужен - удалить. А ошибся - нужен оказывается был - вылетел по обращению к невалидному указателю...

Так что костыль - как раз "беготня за объектами" в поисках их ненадобности и переживании об утечках памяти в случае, ежли не догнал-таки какой-то из объектов.

Тут идет речь о том, что после добавления указателя в коллекцию он также остается у вас. Это первое.

Второе, ни о каких массивах-коллекциях и непрерывном чтении речи не идёт, у вас фрагментированная система получается.

Третье - никто не гарантирует что указатель вы передали именно на объект коллекции.
 
Andrey Pogoreltsev:
Тут идет речь о том, что после добавления указателя в коллекцию он также остается у вас. Это первое.

Второе, ни о каких массивах-коллекциях и непрерывном чтении речи не идёт, у вас фрагментированная система получается.

Третье - никто не гарантирует что указатель вы передали именно на объект коллекции.
  1. Речь шла о том, что автоматическое удаление подсистемой терминала всех созданных вами объектов и помещённых указателей на них в списки вы назвали костылём, при этом ручное управление своими объектами и создание для этого своих костылей вы костылём не считаете
  2. Об этом речи не было в свете ваших заявлений из п1, и как следствие - основной причине моего вам ответа
  3. И об этом тоже, и по той же причине.
 
Igor Makanu:

в справке написано, что при вызове деструктора будут также вызваны деструкторы классов которые использовались

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

не припомню случая, чтобы терминал после выгрузки скрипта не записал в лог предупреждение об не уничтоженных объектах - мой пример не выводит такое предупреждение


по сообщениям разработчиков я находил информацию, что простые структуры или классы в MQL копируются всегда и без проблем, несколько раз я проверял, вроде так и есть, пока пользуюсь возможностями языка


тут в общем к чему все обсуждение - MQL это не С++, я давно перестал искать аналогии между ними, написали разработчики что вот так реализовано - проверил, работает - значит можно использовать, если критично иметь стандартный С++ синтаксис, вынести всю логику в .dll не составляет труда

а треугольный массив с помощью этого можно сделать?

 

Ввиду ограничений языка вряд ли что-то приличное получится. У меня такой костыль родился (лёгенькая обёртка над стандартным массивом)

#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);
}

Для хранения указателей - написать обёртку юник_птр (хотя полноценный не получится, но ауто_птр хотя бы). На мой взгляд, даже такой примитив много удобней шаблонных аналогов из стд.

Причина обращения: