Возможно ли реализовать паттерн singleton на MQL4. - страница 9

 
hoz:

 Я сделал так:

 Но почему-то ошибок много при компиляции. Что не так?

Попытка переложить довольно простой Singleton Майерса на MQL4++ могла бы выглядеть, например, так:

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

Результат исполнения:

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

В статическом методе singleton() создаётся статическая переменная типа Symbol_Properties, но при компиляции выдаётся НЕправомерная ошибка доступа вызова конструктора по умолчанию, поскольку метод, хоть и статический, - имеет доступ ко всем членам, в том числе и private. Поэтому, из-за ошибки реализации MQL4++ пришлось этот конструктор поместить в public. Если исправят, - этого уже не надо будет делать.

По результату исполнения видно, что после вызова change() данные изменились. Это косвенно свидетельствует о том, что функция change() внутри себя получила адрес того же самого объекта, что был получен и в OnStart().

Сейчас, из-за ошибки в MQL4++, это - никакой не Singleton, поскольку таких объектов можно насоздавать много из-за того, что конструктор по умолчанию - public. Если ошибку исправят, и после помещения конструктора по умолчанию в секцию private, - станет полноценной реализацией Singleton'а Майерса на MQL4++.

 
ALXIMIKS:

вы за 2 дня страдания не разобрали что static ведет себя по разному в stuct и в class???

 по ходу, структуры взяли с С и только немного прокачали в плане наследования,

что качается классов, то они полноценные.

 Из-за этого в структурах не обязательно резервировать место под статик переменную

 а в классах резервировать место надо иначе ни как:

 

Неправда, это замечательный компилятор MQL4++ ведёт себя по-разному. Стоит только создать экземпляр объекта, как поведение "выравнивается":

#property strict

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

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

Почему-то это не компилируется (первое и третье - предупреждения, а, вот, второе - полноценная ошибка):

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

Так обязательно ли резервировать в структурах "место под static-переменную"?

А в следующей версии терминала/компилятора - это так же будет (ну, чтобы не бросаться исправлять всё прежде написанное при смене версии)?

 
TheXpert:

Про инкапсуляцию забыл. И удалить можно. А здесь константных указателей нет ) Да и вообще синглтон не лучший паттерн.

А шаблоны хорошо хоть какие-то есть. Для классов наверное только мечтать.



Ну, худший он, или лучший, судить не стану. 

Напомню участникам обсуждения, что неоднократно упомянутые выше РЕЖИМЫ УПРАВЛЕНИЯ ПАМЯТЬЮ - Automatic, Dynamic, Static, Based - не применимы к шаблонам, как бы ни был могуч ООП. 

 
Так обязательно ли резервировать в структурах "место под static-переменную"?
"Да", это просто подметил что можно и "нет" делать, но так не стоит.
 
simpleton:


Сейчас, из-за ошибки в MQL4++, это - никакой не Singleton, поскольку таких объектов можно насоздавать много из-за того, что конструктор по умолчанию - public. Если ошибку исправят, и после помещения конструктора по умолчанию в секцию private, - станет полноценной реализацией Singleton'а Майерса на MQL4++.


Спасибо, не знал что можно тут брать указатель.

С кодом что то вы намудрили, можно проще, жаль нет шаблонов.

 не могу вставить код ((

 class Singleton{

private:

         class SomeClass{

         public:

            int a;

         };

        Singleton(){}

        ~Singleton(){}   

public:

        static SomeClass* Instance(){

                        static SomeClass a();

                        return GetPointer (a);

                }

        };

void OnStart()

{       

        SomeClass* some_ptr = Singleton::Instance();

        some_ptr.a = 5;

        Alert(some_ptr.a);          

}

 
ALXIMIKS:


Спасибо, не знал что можно тут брать указатель.

С кодом что то вы намудрили, можно проще, жаль нет шаблонов.

 не могу вставить код ((

 class Singleton{

private:

         class SomeClass{

         public:

            int a;

         };

        Singleton(){}

        ~Singleton(){}   

public:

        static SomeClass* Instance(){

                        static SomeClass a();

                        return GetPointer (a);

                }

        };

void OnStart()

{       

        SomeClass* some_ptr = Singleton::Instance();

        some_ptr.a = 5;

        Alert(some_ptr.a);          

}

Вот код Майерса для C++:

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

А вот - этот же код, переложенный на MQL4++, и являющийся технической частью класса в примере:

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

Где же тут "мудрёж"?

Ваш пример эксплуатирует ошибки компилятора MQL4++, в частности, использование типа SomeClass в OnStart() - НЕправомерно, потому что это вложенный тип класса Singleton, и "взрослый" компилятор мгновенно обнаруживает ошибку:

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

Однако это не слишком принципиальный момент, поскольку вложенный тип можно указать правильно. Куда принципиальнее то, что тип SomeClass объявлен в секции private класса Singleton, и поэтому использование SomeClass в OnStart() теперь уже принципиально НЕправомерно, о чём "взрослый" компилятор немедленно докладывает:

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

Ваша реализация будет работать, если в компиляторе MQL4++ так и не исправят вакханалию с контролем доступа.

 

1. Маерс, не Маерс, какая в ...опу разница ,главное что бы код работал и делал то что надо и без ошибок В MQL, а не в ++.

2. Ваш код делает то что надо? Неа и точка. Напишите в сервисдеск,  зачем столько ныть все уже все поняли, кто хотел и мог.

3. Мой  пример показал способ обхода ошибок (относительно С++) в MQL, если что-то не нравится смотрите пунк 1 и 2.

4. Касаемо создание указателя на приватный класс - да это промашка MQL, но здесь нет auto чтобы самоопределить тип, по этому хорошо что так работает. \

(п.с. на счет auto может переборщил, надо проверить)

5. Я не нашел способа как в MQL разыменовывать указатель, чтобы получить объект, по этому считаю приватный конструктор копирования и оператор присваивания  излишними.

попытайтесь их использовать, буду рад увидеть способ)) 

 
ALXIMIKS:

1. Маерс, не Маерс, какая в ...опу разница ,главное что бы код работал и делал то что надо и без ошибок В MQL, а не в ++.

2. Ваш код делает то что надо? Неа и точка. Напишите в сервисдеск,  зачем столько ныть все уже все поняли, кто хотел и мог.

3. Мой  пример показал способ обхода ошибок (относительно С++) в MQL, если что-то не нравится смотрите пунк 1 и 2.

4. Касаемо создание указателя на приватный класс - да это промашка MQL, но здесь нет auto чтобы самоопределить тип, по этому хорошо что так работает. \

(п.с. на счет auto может переборщил, надо проверить)

5. Я не нашел способа как в MQL разыменовывать указатель, чтобы получить объект, по этому считаю приватный конструктор копирования и оператор присваивания  излишними.

попытайтесь их использовать, буду рад увидеть способ)) 

 

1. Сейчас - делает, но НЕ то, что надо (пояснения ниже).

2. Если не исправят - и не будет делать. И вряд ли реализуемо будет вообще.

3. Это не способ обхода ошибок, а их эксплуатация.

4. Здесь много, чего нет.

5. В данной версии подобные вещи могут быть возможны, в частности, кажется, у меня промелькивало перед глазами, что конструктор копии не синтезируется, но это не гарантирует, что в следующих версиях он не начнёт синтезироваться. Накладные же расходы на их декларирование, считаю, ничтожны.

Теперь пояснения, почему ваш код не только имеет потенциальные проблемы, о которых я упомянул в предыдущем сообщении, но и почему он в принципе не является singleton'ом и не будет, причём, вне зависимости, исправят вакханалию с доступом или нет:

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

Данный код вполне себе успешно исполняется:

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

Видите, сколько singleton'ов удалось создать, причём они ОДНОВРЕМЕННО существуют?

Что-нибудь в этом смысле для вашего кода поменяется, если исправят вакханалию с доступом?

А в моём коде - поменяется?

Думаете, чем безапеляционнее изложите мысль, тем она вернее будет?

 

да, спасибо за внимательность, вы правы, в данном варианте это тоже не сингелтон.

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

По чему не работает, 'ptr' - cannot call protected member function :

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

да, спасибо за внимательность, вы правы, в данном варианте это тоже не сингелтон.

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

По чему не работает, 'ptr' - cannot call protected member function

Кажется не кажется, а косяков тут ещё много. Жаль, что это замечают еденицы. Я не хочу влезать в полемику, но на самом деле, разница огромнейшая. Некоторые вещи, которые применимы к структурами в С++ в МКЛ4 не работают. Но я промолчу... а то начнут опять задавать вопросы типа:

"Зачем мне это нужно".

Да хоть затем, чтоб можно было не лезть в недоделанный учебник, а просто писать то, то работает в С++ на МКЛ4 и не задумываться работает ли это тут или нет. Больше ничего не нужно мне на данном этапе...