¿Es posible implementar un patrón singleton en MQL4? - página 9

 
hoz:

Yo lo he hecho así:

Pero por alguna razón hay muchos errores al compilar. ¿Qué pasa?

Tratando de transferir un Singleton bastante simple por Myers a MQL4++ podría verse así, por ejemplo:

#property strict

/******************************************************************************/
class Symbol_Properties {
private:
   // Реализация технической части singleton'а
  /******************************************************************************/
public: // Вечно в этом MQL4++ что-то не работает: 'Symbol_Properties::Symbol_Prope…' - cannot call private member function
  Symbol_Properties() {};
private: // Восстанавливаем private
  Symbol_Properties(const Symbol_Properties &p);
  void operator =(const Symbol_Properties &);

public:
  static Symbol_Properties *singleton() {
    static Symbol_Properties sp;
    return GetPointer(sp);
  }

  // Пользовательская часть singleton'а
  /******************************************************************************/
  datetime    gdt_Quote;           // Время поступления последней котировки
  double      gda_Price [2];       // Текущие рыночные цены (0 - Bid, 1- Ask)
  double      gd_Spread;           // Размер спреда в пунктах
  double      gd_Swap;             // Своп
  double      gd_Comission;        // Комиссия
  double      gd_Pt;               // Величина одного пункта
  int         gi_Digits;           // Количество знаков в цене после запятой
  int         gi_StopLevel;        // Минимально-допустимый уровень стоп-лосса/тейк-профита в пунктах
  int         gi_FreezLevel;       // Уровень заморозки ордеров в пунктах
};

/******************************************************************************/
void change() {
  Symbol_Properties *p = Symbol_Properties::singleton(); // Получение singleton'а

  p.gdt_Quote = TimeCurrent();
  p.gda_Price[0] = Bid;
  p.gda_Price[1] = Ask;
}

/******************************************************************************/
void OnStart() {
  Symbol_Properties *p = Symbol_Properties::singleton(); // Получение singleton'а

  Print("gdt_Quote = ", p.gdt_Quote, ", Price = ", p.gda_Price[0], "/", p.gda_Price[1]);
  change();
  Print("gdt_Quote = ", p.gdt_Quote, ", Price = ", p.gda_Price[0], "/", p.gda_Price[1]);
}

Resultado de la ejecución:

01:24:57 Script 3 EURUSDm,H1: loaded successfully
01:24:57 3 EURUSDm,H1: initialized
01:24:57 3 EURUSDm,H1: gdt_Quote = 1970.01.01 00:00:00, Price = 0.0/0.0
01:24:57 3 EURUSDm,H1: gdt_Quote = 2014.09.03 21:24:57, Price = 1.31461/1.3148
01:24:57 3 EURUSDm,H1: uninit reason 0
01:24:57 Script 3 EURUSDm,H1: removed

Un método estático singleton() crea una variable estática de tipo Symbol_Properties, pero en tiempo de compilación se genera un error de acceso a la llamada del constructor por defecto NO válido, porque el método, aunque estático, - tiene acceso a todos los miembros, incluidos los privados. Por lo tanto, debido a un error en la implementación de MQL4++ este constructor tuvo que ser colocado en público. Si lo arreglan, no tendremos que hacerlo más.

El resultado de la ejecución muestra que los datos han cambiado después de la llamada a change(). Esto indica indirectamente que la función change() ha recibido la dirección del mismo objeto dentro de sí misma que también se recibió en OnStart().

Debido al error en MQL4++ esto no es un Singleton en absoluto, ya que el constructor por defecto es público, por lo que muchos de estos objetos pueden ser creados. Si se corrige el error, y tras colocar el constructor por defecto en la sección privada, se convertirá en una implementación completa del Singleton de Myers en MQL4++.

 
ALXIMIKS:

¿No te has dado cuenta en dos días de que la estática se comporta de forma diferente en el conducto y en la clase?

las estructuras parecen tomadas de c y sólo un poco infladas en términos de herencia,

En cuanto a las clases, son de pleno derecho.

Por ello, no es necesario reservar espacio para una variable estática en las estructuras

pero hay que reservar plaza en las clases, de lo contrario no lo harás:

No es cierto, este maravilloso compilador MQL4++ se comporta de manera diferente. En cuanto se crea una instancia del objeto, el comportamiento se "alinea":

#property strict

/******************************************************************************/
struct A {
  static int x;
};

/******************************************************************************/
void OnStart() {
  A y;
}

Por alguna razón no compila (la primera y la tercera son advertencias, pero la segunda es un error en toda regla):

struct has no members, size assigned to 1 byte
unresolved static variable 'A::x'
variable 'y' not used

Entonces, ¿es necesario reservar "espacio para una variable estática" en las estructuras?

Y en la próxima versión del terminal/compilador, ¿será igual (bueno, para no apresurarse a arreglar todo lo escrito antes al cambiar de versión)?

 
TheXpert:

Me olvidé de la encapsulación. Y se puede borrar. Y aquí no hay punteros constantes). De hecho, el singleton no es el mejor patrón.

Y las plantillas son buenas, al menos algunas. Para las clases, probablemente sólo un sueño.



Bueno, si es el peor o el mejor, no voy a juzgar.

Permítanme recordar a los participantes de la discusión que los mencionados MODOS DE GESTIÓN DE LA MEMORIA -Automático, Dinámico, Estático, Basado- no se aplican a las plantillas, por muy poderosa que sea la POO.

 
Так обязательно ли резервировать в структурах "место под static-переменную"?
"Sí", es sólo un punto que también puedes hacer "no", pero no debes hacerlo así.
 
simpleton:


Ahora, debido a un error en MQL4++, esto no es un Singleton, ya que se pueden crear muchos objetos de este tipo, porque el constructor por defecto es público. Si se corrige el error y se coloca el constructor por defecto en la sección privada, se convertirá en una implementación Singleton completa en MQL4++.


Gracias, no sabía que podía tomar un puntero aquí.

El código está desordenado, podría ser más sencillo, siento que no haya plantillas.

No puedo poner el código ((

clase Singleton{

privado:

clase CiertaClase{

público:

int a;

};

Singleton(){}

~Singleton(){}

público:

static SomeClass* Instance(){

static AlgunaClase a();

return GetPointer (a);

}

};

void OnStart()

{

SomeClass* some_ptr = Singleton::Instance();

some_ptr.a = 5;

Alert(some_ptr.a);

}

 
ALXIMIKS:


Gracias, no sabía que se podía coger un puntero aquí.

Te estás metiendo con el código, podría ser más sencillo, lo siento no hay plantillas.

No consigo que el código funcione ((

clase Singleton{

privado:

clase CiertaClase{

público:

int a;

};

Singleton(){}

~Singleton(){}

público:

static SomeClass* Instance(){

estática SomeClass a();

return GetPointer (a);

}

};

void OnStart()

{

SomeClass* some_ptr = Singleton::Instance();

some_ptr.a = 5;

Alerta(algún_ptr.a);

}

Aquí está el código de Myers para C++:

class Singleton
{
private:
    Singleton() {}
    Singleton( const Singleton&);
    Singleton& operator=( Singleton& );
public:
    static Singleton& getInstance() {
        static Singleton  instance;
        return instance;
    }
};

Y aquí está el mismo código transpuesto a MQL4++, que es la parte técnica de la clase del ejemplo:

class Symbol_Properties {
private:
   // Реализация технической части singleton'а
  /******************************************************************************/
public: // Вечно в этом MQL4++ что-то не работает: 'Symbol_Properties::Symbol_Prope…' - cannot call private member function
  Symbol_Properties() {};
private: // Восстанавливаем private
  Symbol_Properties(const Symbol_Properties &p);
  void operator =(const Symbol_Properties &);

public:
  static Symbol_Properties *singleton() {
    static Symbol_Properties sp;
    return GetPointer(sp);
  }

¿Dónde está la "magia" aquí?

Tu ejemplo se aprovecha de los errores del compilador MQL4++, en particular, el uso del tipo SomeClass en OnStart() es inapropiado, porque este es un tipo anidado de la clase Singleton, y el compilador "adulto" detecta instantáneamente un error:

try.cpp:33:9: error: unknown type name 'SomeClass'
        SomeClass* some_ptr = Singleton::Instance();
        ^

Sin embargo, esto no es un punto crucial, ya que un tipo anidado puede ser especificado correctamente. Lo que es más importante es que el tipo SomeClass está declarado en la sección privada de la clase Singleton, y por lo tanto usar SomeClass en OnStart() es ahora fundamentalmente erróneo, lo que el compilador "adulto" reporta inmediatamente:

try.cpp:33:20: error: 'SomeClass' is a private member of 'Singleton'
        Singleton::SomeClass* some_ptr = Singleton::Instance();
                   ^

Su implementación funcionará a menos que el compilador MQL4++ arregle la bacanal de control de acceso.

 

1. Maerse, no Maerse, qué coño importa si el código funciona y hace lo correcto sin errores en MQL y no en ++.

2. ¿Su código hace lo que debe? No, no es así. Ya lo has entendido todo.

Mi ejemplo muestra el manejo de errores (con respecto a C++) en MQL. Si algo no es conveniente, vea los puntos 1 y 2.

4. En cuanto a la creación de un puntero a una clase privada, sí, es un error MQL, pero no hay auto para identificar el tipo, por lo que es bueno que funcione. \

(p.d. Puede que me haya pasado a costa del auto, debería revisarlo)

5. No he encontrado ninguna forma en MQL de desreferenciar un puntero para obtener un objeto, por lo que considero superfluos el constructor de copia privada y el operador de asignación.

Trata de usarlos, estaré encantado de ver el camino))

 
ALXIMIKS:

1. Maerse, no Maerse, qué coño importa si el código funciona y hace lo que debe sin errores en MQL y no en ++.

2. ¿Su código hace lo que debe? No, no es así. Ya lo has entendido todo.

Mi ejemplo muestra el manejo de errores (con respecto a C++) en MQL. Si algo no es conveniente, vea los puntos 1 y 2.

4. En cuanto a la creación de un puntero a una clase privada, sí, es un error MQL, pero no hay auto para identificar el tipo, por lo que es bueno que funcione. \

(p.d. Puede que me haya pasado a costa del auto, debería revisarlo)

5. No he encontrado ninguna forma en MQL de desreferenciar un puntero para obtener un objeto, por lo que considero superfluos el constructor de copia privada y el operador de asignación.

Trata de usarlos, estaré encantado de ver el camino))

1. Ahora - lo hace, pero NO de la manera (explicación más abajo).

2. Si no lo arreglan - tampoco lo hará. Y es poco probable que se pueda aplicar en absoluto.

3. No es una forma de evitar los bichos, es una explotación.

4. Hay muchas cosas que no están ahí.

5. Estas cosas pueden ser posibles en esta versión, en particular, creo que he flasheado que el constructor de copia no se sintetiza, pero eso no garantiza que no se empiece a sintetizar en futuras versiones. Por otro lado, la sobrecarga de declararlas me parece insignificante.

Ahora a explicar por qué su código no sólo tiene los problemas potenciales que mencioné en el post anterior, sino también por qué en principio no es un singleton y no lo será, y si arreglan la bacanal de acceso o no:

#property strict

class Singleton{
private:
         class SomeClass{
         public:
            int a;
         };
        Singleton(){}
        ~Singleton(){}   
public:
        static SomeClass* Instance(){
                        static SomeClass a;
                        return GetPointer (a);
                }
        };
        int i;

void OnStart()
{       
        SomeClass* some_ptr = Singleton::Instance();
        SomeClass obj1;
        SomeClass obj2;

        obj1.a = 3;
        obj2.a = 7;

        some_ptr.a = 5;
        Print("some_ptr.a = ", some_ptr.a);          
        Print("obj1.a = ", obj1.a);          
        Print("obj2.a = ", obj2.a);          
}

Este código se ejecuta con bastante éxito:

10:09:27 Script 3 EURUSDm,H1: loaded successfully
10:09:27 3 EURUSDm,H1: initialized
10:09:27 3 EURUSDm,H1: some_ptr.a = 5
10:09:27 3 EURUSDm,H1: obj1.a = 3
10:09:27 3 EURUSDm,H1: obj2.a = 7
10:09:27 3 EURUSDm,H1: uninit reason 0
10:09:27 Script 3 EURUSDm,H1: removed

¿Ves cuántos singletons han conseguido crearse, y sin embargo, existen ONCE?

¿Cambiaría algo en este sentido para su código si se arreglara la bacanal de acceso?

¿Cambiará en mi código?

¿Cree usted que cuanto más sin disculparse exponga su punto de vista, más correcto será?

 

Sí, gracias por tu atención, tienes razón, tampoco es un singleton en esta variante.

En cuanto a los constructores y operadores implícitos, hazlos explícitos e intenta utilizarlos, me parece que no funcionarán por la imposibilidad de desreferenciar el puntero al objeto

Por qué no funciona, 'ptr' - no puede llamar a la función miembro protegida :

class smart_ptr{
            Singleton* ptr;
      public:        
            smart_ptr(Singleton* val): ptr(val){}          
            smart_ptr(): ptr(NULL){} 
            ~smart_ptr(){delete ptr;}
      };
 
ALXIMIKS:

Sí, gracias por tu atención, tienes razón, tampoco es un singleton en esta variante.

En cuanto a los constructores y operadores implícitos, hazlos explícitos e intenta utilizarlos, me parece que no funcionarán por la imposibilidad de desreferenciar el puntero al objeto

Por qué no funciona, 'ptr' - no puede llamar a la función miembro protegida :

Parece que no funciona y hay muchos más fallos aquí. Es una pena que muy poca gente se dé cuenta de ello. No quiero entrar en una discusión, pero en realidad hay una gran diferencia. Algunas cosas que se aplican a las estructuras en C++ no funcionan en MKL4. Pero me mantendré en silencio... de lo contrario empezarán a hacer preguntas como:

"Para qué lo necesito".

Aunque sólo sea para no meterme en un libro de texto inacabado, sino simplemente escribir cosas que funcionan en C++ en MKL4 y no pensar si funcionan aquí o no. No necesito nada más en este momento...