Est-il possible d'implémenter un modèle singleton dans MQL4 ? - page 9

 
hoz:

Je l'ai fait de cette façon :

Mais pour une raison quelconque, il y a beaucoup d'erreurs lors de la compilation. Qu'est-ce qu'il y a ?

Essayer de transférer un Singleton plutôt simple de Myers à MQL4++ pourrait ressembler à ceci, par exemple :

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

Résultat de l'exécution :

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

Une méthode statique singleton() crée une variable statique de type Symbol_Properties, mais au moment de la compilation, une erreur d'accès à un appel de constructeur par défaut NON valide est générée, car la méthode, bien que statique, - a accès à tous les membres, y compris les membres privés. Par conséquent, en raison d'un bogue dans l'implémentation de MQL4++, ce constructeur a dû être placé en public. S'ils le réparent, nous n'aurons plus à le faire.

Le résultat de l'exécution montre que les données ont changé après l'appel change(). Cela indique indirectement que la fonction change() a reçu l'adresse du même objet à l'intérieur d'elle-même qui a également été reçue dans OnStart().

En raison de l'erreur dans MQL4++, il ne s'agit pas du tout d'un Singleton, puisque le constructeur par défaut est public, de sorte que de nombreux objets de ce type peuvent être créés. Si l'erreur est corrigée, et après que le constructeur par défaut soit placé dans la section privée, il deviendra une implémentation à part entière du Singleton de Myers dans MQL4++.

 
ALXIMIKS:

Vous n'avez pas compris en deux jours que les statiques se comportent différemment en statique et en classe ?

les structures semblent être tirées du c et seulement un peu gonflées en termes d'héritage,

Quant aux classes, elles sont à part entière.

De ce fait, vous ne devez pas réserver d'espace pour une variable statique dans les structures

mais vous devez réserver une place dans les classes, sinon vous n'en aurez pas :

C'est faux, ce merveilleux compilateur MQL4++ se comporte différemment. Dès que vous créez une instance d'objet, le comportement "s'aligne" :

#property strict

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

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

Pour une raison quelconque, il ne compile pas (le premier et le troisième sont des avertissements, mais le deuxième est une véritable erreur) :

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

Est-il donc nécessaire de réserver un "espace pour une variable statique" dans les structures ?

Et dans la prochaine version du terminal/compilateur, ce sera la même chose (enfin, pour ne pas se précipiter à corriger tout ce qui a été écrit avant lors du changement de version) ?

 
TheXpert:

J'ai oublié l'encapsulation. Et il peut être supprimé. Et il n'y a pas de pointeurs constants ici). En fait, le singleton n'est pas le meilleur modèle.

Et les modèles sont bons, du moins certains. Pour les classes, ce n'est probablement qu'un rêve.



Eh bien, que ce soit le pire ou le meilleur, je ne jugerai pas.

Permettez-moi de rappeler aux participants à la discussion que les MODES DE GESTION DE LA MÉMOIRE mentionnés ci-dessus - automatique, dynamique, statique, basée - ne s'appliquent pas aux modèles, quelle que soit la puissance de la POO.

 
Так обязательно ли резервировать в структурах "место под static-переменную"?
"Oui", c'est juste un point que vous pouvez aussi faire "non", mais vous ne devriez pas le faire de cette façon.
 
simpleton:


Maintenant, à cause d'un bug dans MQL4++, ce n'est pas un Singleton, parce que beaucoup de ces objets peuvent être créés, parce que le constructeur par défaut est public. Si l'erreur est corrigée et que le constructeur par défaut est placé dans la section privée, il deviendra une implémentation Singleton à part entière dans MQL4++.


Merci, je ne savais pas que je pouvais prendre un pointeur ici.

Le code est désordonné, il pourrait être plus simple, désolé il n'y a pas de modèles.

Je ne peux pas mettre le code dans ((

classe Singleton{

privé :

classe SomeClass{

public :

int a ;

} ;

Singleton(){}

~Singleton(){}

public :

static SomeClass* Instance(){

statique SomeClass a() ;

retourner GetPointer (a) ;

}

} ;

void OnStart()

{

SomeClass* some_ptr = Singleton::Instance() ;

some_ptr.a = 5 ;

Alert(some_ptr.a) ;

}

 
ALXIMIKS:


Merci, je ne savais pas qu'on pouvait prendre un pointeur ici.

Vous jouez avec le code, ça pourrait être plus simple, désolé il n'y a pas de modèles.

Je n'arrive pas à faire fonctionner le code ((

classe Singleton{

privé :

classe SomeClass{

public :

int a ;

} ;

Singleton(){}

~Singleton(){}

public :

static SomeClass* Instance(){

statique SomeClass a() ;

retourner GetPointer (a) ;

}

} ;

void OnStart()

{

SomeClass* some_ptr = Singleton::Instance() ;

some_ptr.a = 5 ;

Alert(some_ptr.a) ;

}

Voici le code de Myers pour C++ :

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

Et voici le même code transposé en MQL4++, qui est la partie technique de la classe dans l'exemple :

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

Où est la "magie" ici ?

Votre exemple exploite des erreurs du compilateur MQL4++, en particulier, l'utilisation du type SomeClass dans OnStart() est inappropriée, car c'est un type imbriqué de la classe Singleton, et le compilateur "adulte" détecte instantanément une erreur :

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

Toutefois, ce n'est pas un point crucial, car un type imbriqué peut être spécifié correctement. Ce qui est plus important, c'est que le type SomeClass est déclaré dans la section privée de la classe Singleton, et donc l'utilisation de SomeClass dans OnStart() est maintenant fondamentalement erronée, ce que le compilateur "adulte" signale immédiatement :

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

Votre implémentation fonctionnera à moins que le compilateur MQL4++ ne corrige la bacchanale du contrôle d'accès.

 

1. Maerse, pas Maerse, quelle importance si le code fonctionne et fait la bonne chose sans erreurs dans MQL et pas dans ++.

2. Votre code fait-il ce qu'il doit faire ? Non, ce n'est pas le cas. Vous avez déjà tout compris.

Mon exemple montre la gestion des erreurs (par rapport au C++) dans MQL. Si quelque chose ne convient pas, voir les points 1 et 2.

4. Quant à la création d'un pointeur vers une classe privée, oui, c'est une erreur MQL, mais il n'y a pas d'auto pour identifier le type, donc c'est bien que cela fonctionne. \

(p.s. J'ai peut-être exagéré au détriment de l'auto, je devrais vérifier)

5. Je n'ai pas trouvé de moyen dans MQL pour déréférencer un pointeur afin d'obtenir un objet, donc je considère que le constructeur de copie privée et l'opérateur d'affectation sont superflus.

Essayez de les utiliser, je serai heureux de voir le chemin parcouru ;))

 
ALXIMIKS:

1. Maerse, pas Maerse, quelle importance si le code fonctionne et fait la bonne chose sans erreurs dans MQL et pas dans ++.

2. Votre code fait-il ce qu'il doit faire ? Non, ça ne l'est pas. Vous avez déjà tout compris.

Mon exemple montre la gestion des erreurs (par rapport au C++) dans MQL. Si quelque chose ne convient pas, voir les points 1 et 2.

4. Quant à la création d'un pointeur vers une classe privée, oui, c'est une erreur MQL, mais il n'y a pas d'auto pour identifier le type, donc c'est bien que cela fonctionne. \

(p.s. je suis peut-être allé trop loin au détriment de l'auto, je devrais le vérifier)

5. Je n'ai pas trouvé de moyen dans MQL pour déréférencer un pointeur afin d'obtenir un objet, donc je considère que le constructeur de copie privée et l'opérateur d'affectation sont superflus.

Essayez de les utiliser, je serai heureux de voir le chemin parcouru ;))

1. Aujourd'hui, c'est le cas, mais pas de cette manière (explication ci-dessous).

2. S'ils ne le réparent pas, il ne le fera pas non plus. Et il est peu probable qu'il soit possible de le mettre en œuvre.

3. ce n'est pas un moyen de contourner les bugs, c'est de l'exploitation.

4. Il y a beaucoup de choses qui ne sont pas là.

5. De telles choses peuvent être possibles dans cette version, en particulier, je pense avoir flashé que le constructeur de copie n'est pas synthétisé, mais cela ne garantit pas qu'il ne commencera pas à synthétiser dans les versions futures. En revanche, je pense que les frais généraux liés à leur déclaration sont négligeables.

Il faut maintenant expliquer pourquoi votre code présente non seulement les problèmes potentiels que j'ai mentionnés dans le post précédent, mais aussi pourquoi il n'est pas en principe un singleton et ne le sera pas, et s'ils corrigent la bacchanale d'accès ou non :

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

Ce code est exécuté avec succès :

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

Voyez-vous combien de singleton ont réussi à être créés, alors qu'ils n'existent qu'une seule fois ?

Est-ce que quelque chose dans ce sens changerait pour votre code si la bacchanale d'accès était corrigée ?

Est-ce que ça va changer dans mon code ?

Pensez-vous que plus votre point de vue est irréprochable, plus il sera correct ?

 

Oui, merci de votre attention, vous avez raison, ce n'est pas un singleton dans cette variante non plus.

Concernant les constructeurs et opérateurs implicites - rendez-les explicites et essayez de les utiliser, il me semble qu'ils ne fonctionneront pas en raison de l'impossibilité de déréférencer le pointeur vers l'objet.

Pourquoi cela ne fonctionne-t-il pas, 'ptr' - ne peut pas appeler une fonction membre protégée :

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

Oui, merci de votre attention, vous avez raison, ce n'est pas un singleton dans cette variante non plus.

Concernant les constructeurs et opérateurs implicites - rendez-les explicites et essayez de les utiliser, il me semble qu'ils ne fonctionneront pas en raison de l'impossibilité de déréférencer le pointeur vers l'objet.

Pourquoi cela ne fonctionne-t-il pas, 'ptr' - ne peut pas appeler une fonction membre protégée :

Cela ne semble pas fonctionner et il y a beaucoup plus de bogues ici. C'est dommage que très peu de gens le remarquent. Je ne veux pas me lancer dans une polémique, mais en fait, il y a une énorme différence. Certaines choses qui s'appliquent aux structures en C++ ne fonctionnent pas en MKL4. Mais je vais me taire... sinon ils vont commencer à poser des questions comme :

"Pourquoi en ai-je besoin".

Ne serait-ce que pour ne pas me lancer dans un manuel inachevé, mais simplement écrire des choses qui fonctionnent en C++ dans MKL4 et ne pas se demander si elles fonctionnent ici ou non. Je n'ai besoin de rien d'autre à ce stade...