È possibile implementare un modello singleton in MQL4. - pagina 9

 
hoz:

L'ho fatto in questo modo:

Ma per qualche motivo ci sono molti errori durante la compilazione. Cosa c'è che non va?

Cercare di trasferire un Singleton piuttosto semplice da Myers a MQL4++ potrebbe apparire così, per esempio:

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

Risultato dell'esecuzione:

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 metodo statico singleton() crea una variabile statica di tipo Symbol_Properties, ma in fase di compilazione viene generato un errore di accesso alla chiamata di costruttore NON valido, perché il metodo, sebbene statico, - ha accesso a tutti i membri, compresi quelli privati. Pertanto, a causa di un bug nell'implementazione di MQL4++ questo costruttore doveva essere messo in pubblico. Se lo aggiustano, non dovremo più farlo.

Il risultato dell'esecuzione mostra che i dati sono cambiati dopo la chiamata change(). Questo indica indirettamente che la funzione change() ha ricevuto l'indirizzo dello stesso oggetto al suo interno che è stato ricevuto anche in OnStart().

A causa dell'errore in MQL4++ questo non è affatto un Singleton, poiché il costruttore di default è pubblico, quindi possono essere creati molti oggetti del genere. Se l'errore viene corretto, e dopo che il costruttore di default viene messo nella sezione privata, diventerà un'implementazione completa di Myers' Singleton in MQL4++.

 
ALXIMIKS:

Non hai capito in due giorni che la statica si comporta in modo diverso in stuct e in classe?

le strutture sembrano essere prese da c e solo un po' pompate in termini di ereditarietà,

Per quanto riguarda le classi, sono complete.

Per questo motivo, non è necessario riservare spazio per una variabile statica nelle strutture

ma bisogna riservare uno spazio nelle classi, altrimenti non si può:

Non è vero, questo meraviglioso compilatore MQL4++ si comporta diversamente. Non appena si crea un'istanza dell'oggetto, il comportamento si "allinea":

#property strict

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

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

Per qualche motivo non compila (il primo e il terzo sono avvertimenti, ma il secondo è un vero e proprio errore):

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

Quindi è necessario riservare "spazio per una variabile statica" nelle strutture?

E nella prossima versione del terminale/compilatore, sarà lo stesso (bene, per non correre a sistemare tutto quello che è stato scritto prima quando si cambia versione)?

 
TheXpert:

Ho dimenticato l'incapsulamento. E può essere cancellato. E qui non ci sono puntatori costanti). E in generale, il singleton non è il modello migliore.

E i modelli sono buoni, almeno alcuni. Per le classi, probabilmente solo un sogno.



Beh, che sia il peggiore o il migliore, non giudicherò.

Permettetemi di ricordare ai partecipanti alla discussione che le modalità di gestione della memoria menzionate sopra - automatica, dinamica, statica, basata - non si applicano ai template, non importa quanto sia potente l'OOP.

 
Так обязательно ли резервировать в структурах "место под static-переменную"?
"Sì", è solo un punto che si può anche fare "no", ma non si dovrebbe fare così.
 
simpleton:


Ora, a causa di un bug in MQL4++, questo non è un Singleton, perché molti oggetti del genere possono essere creati, perché il costruttore di default è pubblico. Se l'errore viene corretto e il costruttore di default viene messo nella sezione privata, diventerà un'implementazione Singleton a tutti gli effetti in MQL4++.


Grazie, non sapevo di poter prendere un puntatore qui.

Il codice è incasinato, potrebbe essere più semplice, mi dispiace che non ci siano modelli.

Non posso mettere il codice ((

classe Singleton{

privato:

classe SomeClass{

pubblico:

int a;

};

Singleton(){}

~Singleton(){}

pubblico:

static SomeClass* Instance(){

statico SomeClass a();

return GetPointer (a);

}

};

void OnStart()

{

SomeClass* some_ptr = Singleton::Instance();

some_ptr.a = 5;

Alert(some_ptr.a);

}

 
ALXIMIKS:


Grazie, non sapevo che si potesse prendere un puntatore qui.

Stai pasticciando con il codice, potrebbe essere più semplice, mi dispiace che non ci siano modelli.

Non riesco a far funzionare il codice ((

classe Singleton{

privato:

classe SomeClass{

pubblico:

int a;

};

Singleton(){}

~Singleton(){}

pubblico:

static SomeClass* Instance(){

statico SomeClass a();

return GetPointer (a);

}

};

void OnStart()

{

SomeClass* some_ptr = Singleton::Instance();

some_ptr.a = 5;

Alert(some_ptr.a);

}

Ecco il codice di Myers per C++:

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

Ed ecco lo stesso codice trasposto in MQL4++, che è la parte tecnica della classe nell'esempio:

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

Dov'è la "magia" qui?

Il tuo esempio sfrutta gli errori del compilatore MQL4++, in particolare, l'uso del tipo SomeClass in OnStart() è inappropriato, perché questo è un tipo annidato della classe Singleton, e il compilatore "adulto" rileva immediatamente un errore:

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

Tuttavia, questo non è un punto cruciale, poiché un tipo annidato può essere specificato correttamente. Ciò che è più importante è che il tipo SomeClass è dichiarato nella sezione privata della classe Singleton, e quindi usare SomeClass in OnStart() è ora fondamentalmente sbagliato, cosa che il compilatore "adulto" segnala immediatamente:

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

La vostra implementazione funzionerà a meno che il compilatore MQL4++ non corregga i baccanali del controllo di accesso.

 

1. Maerse, non Maerse, che cazzo importa se il codice funziona e fa la cosa giusta senza errori in MQL e non in ++.

2. Il vostro codice fa quello che dovrebbe? No, non lo fa. Avete già capito tutto.

Il mio esempio ha dimostrato il workaround degli errori (riguardanti il C++) in MQL. Se qualcosa non è conveniente, vedi i punti 1 e 2.

4. Per quanto riguarda la creazione di un puntatore a una classe privata, sì, è un errore MQL, ma non c'è un auto per identificare il tipo, quindi è bene che funzioni. \

(p.s. Forse ho esagerato a spese dell'auto, dovrei controllare)

5. Non ho trovato alcun modo in MQL di dereferenziare un puntatore per ottenere un oggetto, quindi considero superflui il costruttore di copie private e l'operatore di assegnazione.

Prova a usarli, sarò felice di vedere il modo))

 
ALXIMIKS:

1. Maerse, non Maerse, che cazzo importa se il codice funziona e fa la cosa giusta senza errori in MQL e non in ++.

2. Il vostro codice fa quello che dovrebbe? No, non è così. Avete già capito tutto.

Il mio esempio mostra la gestione degli errori (rispetto al C++) in MQL. Se qualcosa non è conveniente, vedi i punti 1 e 2.

4. Per quanto riguarda la creazione di un puntatore a una classe privata, sì, è un errore MQL, ma non c'è un auto per identificare il tipo, quindi è bene che funzioni. \

(p.s. forse ho esagerato a spese dell'auto, dovrei controllare)

5. Non ho trovato alcun modo in MQL di dereferenziare un puntatore per ottenere un oggetto, quindi considero superflui il costruttore di copie private e l'operatore di assegnazione.

Prova a usarli, sarò felice di vedere il modo))

1. Ora - lo fa, ma NON in questo modo (spiegazione sotto).

2. Se non lo aggiustano - non lo farà neanche lui. Ed è improbabile che sia implementabile del tutto.

3. Non è un modo per aggirare i bug, è sfruttamento.

4. Ci sono molte cose che non ci sono.

5. Queste cose possono essere possibili in questa versione, in particolare, credo di aver fatto balenare che il costruttore di copie non è sintetizzato, ma questo non garantisce che non inizierà a sintetizzare nelle versioni future. L'overhead di dichiararli, d'altra parte, penso sia trascurabile.

Ora per spiegare perché il tuo codice non solo ha i potenziali problemi che ho menzionato nel post precedente, ma anche perché non è in linea di principio un singleton e non lo sarà, e se risolvono i baccanali di accesso 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);          
}

Questo codice viene eseguito con successo:

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

Vedete quanti singleton sono riusciti ad essere creati, eppure non esistono ancora?

Cambierebbe qualcosa in questo senso per il vostro codice se il baccanale dell'accesso fosse fissato?

Cambierà nel mio codice?

Pensate che più non vi scusate, più il vostro punto di vista sarà corretto?

 

Sì, grazie per l'attenzione, hai ragione, non è un singoletto neanche in questa variante.

Per quanto riguarda i costruttori e gli operatori impliciti - rendeteli espliciti e provate a usarli, mi sembra che non funzionino a causa dell'impossibilità di dereferenziare il puntatore all'oggetto

Perché non funziona, 'ptr' - non può chiamare la funzione membro protetta :

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

Sì, grazie per l'attenzione, hai ragione, non è un singoletto neanche in questa variante.

Per quanto riguarda i costruttori e gli operatori impliciti - rendeteli espliciti e provate a usarli, mi sembra che non funzionino a causa dell'impossibilità di dereferenziare il puntatore all'oggetto

Perché non funziona, 'ptr' - non può chiamare la funzione membro protetta :

Non sembra funzionare e ci sono molti altri bug qui. È un peccato che poche persone lo notino. Non voglio entrare in una discussione, ma in realtà c'è un'enorme differenza. Alcune cose che si applicano alle strutture in C++ non funzionano in MKL4. Ma tacerò... altrimenti cominceranno a fare domande come:

"Perché ne ho bisogno".

Se non altro per non entrare in un libro di testo incompiuto, ma semplicemente scrivere cose che funzionano in C++ in MKL4 e non pensare se funzionano qui o no. Non ho bisogno di nient'altro in questa fase...