初心者の方からの質問 MQL5 MT5 MetaTrader 5 - ページ 1333

 
Mikhail Tkachev:

返信ありがとうございます、あなたは全く邪悪ではありません)
これで全て納得です)
UPD
この構築も有効です。

At()メソッドが何を返すのかに注目してください。NULLを返した場合、クリティカルエラーで クラッシュします。オブジェクトへのポインタにアクセスする前に、それがNULLでないことを確認する。

 
Mikhail Tkachev:

すでに気づいている)
つまり、解決策はグローバルに空のオブジェクトを宣言すること...。
また、その人数が事前にわからない場合は?ただ、"with reserve" と宣言するだけでいいのですか? :)
追伸:このようなオブジェクトの宣言の仕方は、組み込みのヘルプにはありませんでした。

昔々、Artyomがこんな授業を書いてくれた。その仕組みを詳しく説明することはできませんが。でも、アルテムは覚えているだろうし、説明もできるだろう。以下は、クラスそのものです。

#include <Arrays\ArrayObj.mqh>
/********************************************************************\
|   Класс Новый бар                                                  |
\********************************************************************/
class CNewBar : public CObject
  {
private:
  string            m_symbol;
  ENUM_TIMEFRAMES   m_timeframe;
  datetime          m_time;
  datetime          Time(void);                                       //  Возвращает время нулевого бара
  string            Symbol(void)         { return this.m_symbol;    }
public:
  ENUM_TIMEFRAMES   Timeframe(void)      { return this.m_timeframe; }
  datetime          GetTime(void)        { return this.m_time;      } //  Возвращает время последнего обращения
  bool              IsNewBar(void);                                   //  Основная функция класса

                    CNewBar(const string symbol,const ENUM_TIMEFRAMES timeframe);
                   ~CNewBar(void){;}
  };
//+------------------------------------------------------------------+
//|    Конструктор                                                   |
//+------------------------------------------------------------------+
CNewBar::CNewBar(const string symbol,const ENUM_TIMEFRAMES timeframe) : m_time(0)
  {
   this.m_symbol = symbol;
   this.m_timeframe = (timeframe == PERIOD_CURRENT ? Period() : timeframe);
  }
//+------------------------------------------------------------------+
//| CNewBar Time Возвращает время нулевого бара                      |
//+------------------------------------------------------------------+
datetime CNewBar::Time(void)
  {
   datetime array[1], ret;
   ret = CopyTime(this.m_symbol, this.m_timeframe, 0, 1, array) == 1 ? array[0] : 0;
   return(array[0]);
  }
//+------------------------------------------------------------------+
//| CNewBar IsNewBar Основная функция класса                         |
//+------------------------------------------------------------------+
bool CNewBar::IsNewBar(void)
  {
   datetime tm = this.Time();
   if(tm == 0)
      return false;
   if(tm != this.m_time)
     {
      this.m_time = tm;
      return true;
     }
   return false;
  }

そして、OnInit()内でポインタを作成するループは以下の通りです。

   for(int i = 0; i < ArraySize(Rates); i++)
     {
       CNewBar* nb = new CNewBar(Rates[i].m_Symbols, timefram);
       if(nb != NULL)
         {
          list_new_bar.Add(nb);
          Print(nb.IsNewBar(), " ***** ", Rates[i].m_Symbols, " ***** ", nb.Time());
         }
     }

で、OnTimer()で

void OnTimer()
{
 int total = list_new_bar.Total();
 for(int i = 0; i < ArraySize(Rates); i++)
  {
   CNewBar* nb = list_new_bar.At(i);
   if(nb == NULL)
    continue;
   bool new_bar = nb.IsNewBar();
   if(new_bar)
    {// и дальше………

ArraySize(Rates)は、処理する文字が列挙された構造体の配列の大きさ である。

 
Alexey Viktorov:

アルチョムは以前、私にこんな授業を書いてくれた。その仕組みを詳しく説明することはできません。でも、アルチョムは覚えているだろうし、説明もできるだろう。さて、クラスそのものは以下の通りです。

そして、OnInit()内でポインタを作成するループは以下の通りです。

で、OnTimer()で

ArraySize(Rates)は、処理する文字が列挙された構造体の配列の大きさ である。

これです。

for(int i = 0; i < ArraySize(Rates); i++)

Rates 配列から文字を読み込んで、新しい bar クラスのインスタンスを作成し、リストに追加しているという理由からです。

追加に失敗した場合、新しいバークラスのインスタンスへのポインタのリストのサイズは、Rates配列のサイズと一致しません。

一般的には、このようなものであることが必要です。

void OnTimer()
  {
   int total = list_new_bar.Total();
   for(int i = 0; i < total; i++)
   {
   CNewBar* nb = list_new_bar.At(i);
   if(nb == NULL)
      continue;
   if(nb.IsNewBar())
     {// и дальше………

そして、ここでも追加に成功したかどうかのチェックが必要です。

   for(int i = 0; i < ArraySize(Rates); i++)
     {
       CNewBar* nb = new CNewBar(Rates[i].m_Symbols, timefram);
       if(nb != NULL)
         {
          list_new_bar.Add(nb);
          Print(nb.IsNewBar(), " ***** ", Rates[i].m_Symbols, " ***** ", nb.Time());
         }
     }

というようなものです。

   for(int i = 0; i < ArraySize(Rates); i++)
     {
      CNewBar *nb = new CNewBar(Rates[i].m_Symbols, timefram);
      if(nb==NULL)
         continue;
      if(!list_new_bar.Add(nb))
        {
         delete nb;
         continue;
        }
      Print(nb.IsNewBar(), " ***** ", Rates[i].m_Symbols, " ***** ", nb.Time());
     }
新しいオブジェクトへのポインタが誤ってリストに追加された場合のメモリリークを回避するため
 
Artyom Trishkin:

これです。

Ratesの配列から文字を読み込んで、新しいbarクラスのインスタンスを作成し、リストに追加するためです。

追加に失敗した場合、新しいバークラスのインスタンスへのポインタのリストのサイズは、Rates配列のサイズと一致しません。

一般的には、このようなものであることが必要です。

そして、ここでも追加に成功したかどうかのチェックが必要です。

というようなものです。

新しいオブジェクトへのポインタが誤ってリストに追加された場合のメモリリークを回避するため

ありがとうございます。了解です、こちらに訂正 させていただきます:)))

私はcontinue;オペレータが 嫌いで、使わないようにしています。絶望的なケースに限る。

      if(nb==NULL)
         continue;

とはどう違うのか

      if(nb!=NULL)
       {
       }
もうひとつは、エラー時に失敗したポインタが削除される場合です...しかし、ここでも、嫌われた継続をせずに、単にPrint()を削除すればよいのです。デバッグ中、何が起こっているのか理解するために必要なもので、作業中に何かエラーが起こっても、何が悪いのかどうせ理解できない...ログを理解するよりOSを再インストールする方が簡単だ。


せっかくなので、ポインタとクラス変数の違い、どちらが望ましいか、細かいことは抜きにして教えてください。インターネットでは、わかりにくい内容でも読むことができますね。いわば、表面的な理解で十分なのです...。

 
Artyom Trishkin:

At()メソッドが何を返すのかに注目してください。NULLを返した場合、クリティカルエラーで クラッシュします。オブジェクトへのポインタにアクセスする前に、それがNULLでないことを確認する。

Artemさん、貴重なコメントありがとうございます)

 
Alexey Viktorov:

ありがとうございます。なるほど、こういう風に修正 するのか... :)))

私はcontinue演算 子が嫌いで、なるべく使わないようにしています。絶望的なケースに限る。

との違いについて


ループの反復は終了せず、新しいループが始まるわけでもなく、次の反復に移ります。論理が変わる。

 
Alexey Viktorov:

アルチョムは以前、私にこんな授業を書いてくれた。その仕組みを詳しく説明することはできません。でも、アルチョムは覚えているだろうし、説明もできるだろう。とにかく、このクラスそのものを紹介します。

//+------------------------------------------------------------------+
//| CNewBar Time Возвращает время нулевого бара                      |
//+------------------------------------------------------------------+
datetime CNewBar::Time(void)
  {
   datetime array[1], ret;
   ret = CopyTime(this.m_symbol, this.m_timeframe, 0, 1, array) == 1 ? array[0] : 0;
   return(array[0]);
 }

Alexeyさん、こんなに詳しいお返事をありがとうございます。
引用したコード片の変数retの目的が不明です...。
どのような場合にarray[0]を返すのか、何のために計算するのか?
P.S.
そして、なぜこれをクラスメソッドで 使用するのか?私たちは、この特別なクラスのメンバーと一緒に...


 
Alexey Viktorov:

ありがとうございます。なるほど、こういう風に修正 するのか... :)))

私はcontinue演算 子が嫌いで、なるべく使わないようにしています。絶望的なケースに限る。

とはどう違うのか

もうひとつは、エラーが発生したときに、失敗したポインタを削除してしまう場合です...しかし、ここでも、嫌われるcontinueをせずに、Print()を削除すればいいのです。デバッグ中、何が起こっているのか理解するために必要なもので、作業中に何かエラーが起こっても、どうせ何が悪いのか理解できない...ログを理解するくらいなら、OSを再インストールした方がいい。


せっかくなので、ポインタとクラス変数の違い、どちらが望ましいか、細かいことは抜きにして教えてください。インターネットでは、わかりにくい内容でも読むことができますね。表面的な理解で十分なのです、いわば。

不要な括弧をなくすことで、森や枝を作らないようにしているんです。印刷がなければ括弧は不要で、オブジェクトを削除すればよい。

新しい演算子で、物理的に「どこか」にある何らかの機構を作る。new 演算子は、この「どこか」のアドレスを返す。そして、この「仕組み」を参照するのは、それしかありません。
そして、その機構の中にあるボルトは、可変式です。
 
Valeriy Yastremskiy:

その繰り返しは終わることなく、新たなサイクルが始まるわけでもなく、次のIfへと進んでいくのです。論理が変わる。

新しいサイクルのイテレーションに移行し、その中で
 
Mikhail Tkachev:

Alexeyさん、こんなに詳しく答えてくれてありがとうございます。
このコードでは、ret変数の用途がよくわかりません。
メソッドがとにかくarray[0]を返す場合、なぜ計算されるのですか?


Alexeyは私が渡したコードの中で何かを作り直しました。あるいは私も見逃していたのかもしれません。もう覚えていないことを説明する簡単な例として、「土下座」を書きました。
理由: