Biblioteca de clases genéricas - errores, descripción, preguntas, características de uso y sugerencias - página 26

 
Andrey Pogoreltsev:

Se crean copias de objetos en AddValue a través de new, pero no se liberan en el destructor, sólo se borra la lista de punteros.

dice que cuando se llama a un destructor, también se llamará a los destructores de las clases utilizadas

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

No recuerdo ningún caso en el que el terminal no escribiera en el registro una advertencia sobre los objetos no destruidos después de la descarga del script - mi ejemplo no muestra tal advertencia


Andrey Pogoreltsev:

En segundo lugar, deberías haberlo hecho correctamente con el constructor de copia en lugar del operador de asignación. Pero todo esto es IMHO)

He encontrado información de desarrolladores de que las estructuras o clases simples en MQL se copian siempre sin problemas, lo he comprobado varias veces y parece ser cierto, siempre y cuando utilice las características del lenguaje


De esto se trata la discusión - MQL no es C++, he dejado de buscar analogías entre ellos, si los desarrolladores escribieron que así es como se implementa - lo comprobé, funciona - así que puedes usarlo, si la sintaxis estándar de C++ es crucial, es fácil poner toda la lógica en .dll

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

Se crean copias de objetos en AddValue a través de new, pero no se liberan en el destructor, sólo se borra la lista de punteros.

¡Oh, Dios! Y cómo se puede borrar una instancia de una clase creada mediante new en el destructor. Intenta hacerlo. No funcionará.

Sólo se puede hacer en el destructor de alguna otra clase.

 
Nikolai Semko:

¡Oh, mierda! Y cómo se puede eliminar una instancia de una clase creada mediante new en el destructor. Puedes probarlo. No funcionará.

Sólo se puede hacer en el destructor de otra clase.

Me refería al destructor de otra clase. Me refería a los elementos creados a través de new en el métodoAddValue

 
Igor Makanu:

help dice que cuando se llama a un destructor, los destructores de las clases utilizadas también serán llamados

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

No recuerdo un caso en el que el terminal no escribiera una advertencia sobre los objetos no destruidos en el registro después de que se descargara el script - mi ejemplo no muestra tal advertencia


He escuchado de los desarrolladores que las estructuras o clases simples en MQL se copian siempre sin problemas, lo he comprobado varias veces y parece ser cierto, hasta ahora uso las posibilidades del lenguaje


De esto se trata la discusión - MQL no es C++, he dejado de buscar analogías entre ellos, los desarrolladores escribieron que así es como se implementa - lo comprobé, funciona - así que puedes usarlo, si la sintaxis estándar de C++ es crucial, no debería preocuparme poner toda la lógica en .dll.

Sí, lo vi en la ayuda... Algo muy implícito, parece más bien una muleta, en lugar de unique_ptr...

 
Andrey Pogoreltsev:

Sí, lo vi en la ayuda... Algo muy implícito, más bien una muleta en lugar de unique_ptr...

Y es tan práctico que ni siquiera puedo llamarlo muleta:

Cree un objeto de cualquier clase, póngalo en una lista de almacenamiento y ya no tendrá que preocuparse de eliminarlo: el subsistema de terminal lo limpia por sí mismo.
Pero también se puede establecer el funcionamiento manual y "ejecutar" para todos los objetos recién creados tratando de rastrear cuándo, dónde y para qué se creó y si se necesita ahora. Si no es necesario, elimínelo. Pero cuando te equivocas, resulta que era necesario: se bloquea al acceder a un puntero no válido...

Así que la muleta no es más que "perseguir objetos" buscando su inutilidad y preocupándose por las fugas de memoria si algún objeto no ha sido atrapado.

 
Andrey Pogoreltsev:

En segundo lugar, la forma correcta de hacerlo es a través del constructor de copia, no del operador de asignación. Pero todo esto es IMHO)

¿Puedes darme un ejemplo de cómo copiarlo correctamente para esta plantilla?

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

He utilizado la ayuda para escribir el método AddValuehttps://www.mql5.com/ru/docs/basis/types/classes

Me he devanado los sesos, pero no veo otra solución en MQL que la que he escrito en mi ejemplo.

Muéstrame tu implementación de un correcto almacenamiento de datos

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

Y es tan práctico que ni siquiera se le puede llamar muleta:

Cree cualquier objeto de cualquier clase, póngalo en la lista de almacenamiento y ya no tendrá que preocuparse de eliminarlo: el subsistema de terminales lo limpia por sí mismo.
Pero también se puede establecer la operación manual y "ejecutar" para todos los objetos recién creados tratando de averiguar cuándo, dónde y para qué se creó y si se necesita ahora. Si no es necesario, elimínelo. Pero cuando te equivocas, resulta que era necesario: se bloquea al acceder a un puntero no válido...

Así que la muleta no es más que "perseguir objetos" buscando su inutilidad y preocupándose por las fugas de memoria si algún objeto no ha sido atrapado.

Lo que quiero decir aquí es que cuando añades un puntero a la colección, también se queda contigo. Esto es lo primero.

En segundo lugar, no estamos hablando de arrays-colecciones y lectura continua; tienes un sistema fragmentado.

En tercer lugar, no se puede garantizar que se haya pasado un puntero a un objeto de la colección.
 
Andrey Pogoreltsev:
El punto aquí es que una vez que agregas un puntero a la colección, también se queda contigo. Eso es lo primero.

En segundo lugar, no estamos hablando de arrays-colecciones y lectura continua; tienes un sistema fragmentado.

En tercer lugar, nadie garantiza que hayas pasado un puntero al objeto de la colección.
  1. Me refería a que la eliminación automática por parte del subsistema terminal de todos tus objetos creados y poner punteros a ellos en listas lo llamas muleta, y no consideras muleta la manipulación manual de tus objetos y la creación de muletas para ello.
  2. Eso no era parte de lo que dijiste en el punto 1, y es la razón principal por la que respondí.
  3. Eso también, y por la misma razón.
 
Igor Makanu:

help dice que cuando el destructor es llamado, los destructores de las clases utilizadas también serán llamados

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

No recuerdo un caso en el que el terminal no escribiera una advertencia sobre los objetos no destruidos en el registro después de que se descargara el script - mi ejemplo no muestra tal advertencia


He escuchado de los desarrolladores que las estructuras o clases simples en MQL se copian siempre sin problemas, lo he comprobado varias veces y parece ser cierto, hasta ahora uso las posibilidades del lenguaje


De esto se trata la discusión - MQL no es C++, he renunciado a buscar analogías entre ellos, los desarrolladores escribieron que así es como se implementa - lo comprobé, funciona - así que puedes usarlo, si la sintaxis estándar de C++ es crucial, puedes escribir fácilmente toda la lógica en .dll

¿Se puede hacer una matriz triangular con esto?

 

Debido a las limitaciones del idioma, es poco probable que funcione algo decente. Tengo esta muleta (una envoltura ligera sobre un array estándar).

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

Para almacenar punteros, escribe un wrapper unic_ptr (aunque no puedes conseguir uno completo, sino auto_ptr al menos). En mi opinión, incluso esta primitiva es mucho más conveniente que las plantillas homólogas de std.