MQL5 でのアサーション
イントロダクション
アサーションは、プログラムの任意の場所にチェック可能な特殊な構造です。一般的には、(主に別の関数やマクロなど)のコードの形で実装されます。このコードは、特定の表現の真の値をチェックします。falseの場合には、該当するメッセージが表示され、プログラムが停止されます。したがって、trueである場合、 前提が満たされ意図したとおりにすべてが動作します。それ以外の場合、プログラムのエラーを特定することができます。
例えば、プログラムのある値 X が0未満であってはならないとき、下記の文ができます。: X が0か0を超えていることを確認。もしXが0未満の場合は、関連するメッセージが表示され、プログラマは、コードを修正することができます。
アサーションは、コンポーネントを再利用するときや大規模なプロジェクトで特に有用です。
アサーションは通常、プログラムの動作中に稼働させずに、上記のような状況でのみ活用するべきです。原則として、アサーションはプログラムの開発およびデバッグの段階で適用すると有用ですが、最終版では残すべきではありません。すべてのアサーションは最終版のコンパイル時には除去されなければなりません。これは通常、条件付きのコンパイルをすることによって実現できます。
MQL5でのアサーションメカニズムの例
次の機能は、通常、アサーションメカニズムによって実装されています。
- テキストの表示を確認。
- エラーが検出されたソースコードを含むファイル名の表示。
- エラーが検出された関数名の表示。
- ソースファイルの行番号の表示。
- コードの書き込み段階でプログラマによって指定された、任意のメッセージを表示。
- エラーを見つけた後、プログラム終了。
- 類似のメカニズムを使用してコンパイルされたプログラムからすべてのアサーションを除外。
ほぼすべての機能が標準関数を使用して実装することができます。(ポイント6から)マクロと条件付きコンパイル MQL5言語のメカニズム。を参照。具体的には、以下はすべての選択肢のうちの2つです。
Option N1(プログラムを終了させないソフトバージョン)
#define DEBUG #ifdef DEBUG #define assert(condition, message) \ if(!(condition)) \ { \ string fullMessage= \ #condition+", " \ +__FILE__+", " \ +__FUNCSIG__+", " \ +"line: "+(string)__LINE__ \ +(message=="" ? "" : ", "+message); \ \ Alert("Assertion failed! "+fullMessage); \ } #else #define assert(condition, message) ; #endif
Option N2 (プログラムを終了するハードバージョン)
#define DEBUG #ifdef DEBUG #define assert(condition, message) \ if(!(condition)) \ { \ string fullMessage= \ #condition+", " \ +__FILE__+", " \ +__FUNCSIG__+", " \ +"line: "+(string)__LINE__ \ +(message=="" ? "" : ", "+message); \ \ Alert("Assertion failed! "+fullMessage); \ double x[]; \ ArrayResize(x, 0); \ x[1] = 0.0; \ } #else #define assert(condition, message) ; #endif
アサートマクロ
まず、 DEBUG識別子を宣言します。この識別子が宣言されたままの場合は、#ifdefの条件付きコンパイル式のブランチが有効になり、また、フル機能のアサートマクロがプログラムに含まれます。それ以外の場合は、(#elseブランチ)、任意の操作の実行につながらないアサートマクロが、プログラムに含まれます。
フル機能のマクロアサートは次のように構築されています。まず、条件が実行されます。それがfalseの場合は、 fullMessageメッセージが表示されます。 fullMessageは次の要素から構成されています。
- 式のテキストのチェック(#condition)。
- マクロが呼び出されたソースコードを含むファイル名(__FILE__)。
- マクロが呼び出された関数やメソッドのシグネチャ (__FUNCSIG__)。
- マクロを呼び出すソースコードファイル内の行番号(__LINE__).。
- 空ではない場合は、メッセージをマクロに転送(message)。
(警告)メッセージを表示した後、存在しない配列要素に値を代入しようとすると、時間の実行エラーにつながり、クラッシュします。
プログラムを停止するこの方法は、そのサブウィンドウで動作するインジケーターに副作用が発生します。:つまり、ターミナル内に残ってしまうので、手動でクローズする必要があります。また、ターミナルがクラッシュする際、プログラムの動作中に作成された、グラフィカル・オブジェクト、グローバル変数、ファイルなどが存在する場合があります。この動作が許容できない場合、最初のマクロを使用する必要があります。
説明。MQL5でこの記事を書いている時点では、緊急停止を実行するためのプログラムメカニズムはありませんでした。プログラムを確実にクラッシュさせる方法として、ランタイムエラーが代替案となりました。
このマクロは、インクルードされたassert.mqh中に配置することができます。<data folder>/MQL5/Include. このファイル(option N2)は、この記事に添付されています。
以下のコードは、アサーションと、その演算結果の例が含まれています。
EAのコードでのアサートマクロの使用例
#include <assert.mqh> intOnInit() { assert(0 > 1, "my message") return(INIT_SUCCEEDED); } void OnDeinit(const int reason) { } void OnTick() { }
ここでは、文字通り「0が1より大きいか確認すること」を意味するアサーションを行います。このアサーションは、明らかに偽で、エラーメッセージが表示されます。:
図1。アサーションの例
アサーションを使用するための一般的な原則
アサーションは、プログラムの不測の事態を識別し、想定内の状況を制御するために使用されます。例えば、アサーションは以下の条件を確認するために使用することができます。
- 関数やメソッドの値を結果として、入力および出力パラメータの値は、予想される範囲内に収まります。
入力と出力をチェックするためのアサーションの使用例double CMyClass::SomeMethod(const double a) { //---入力パラメータの値をチェック assert(a>=10,"") assert(a<=100,"") //---結果の値を計算 double result=...; //---結果の値をチェック assert(result>=0,"") return result; }
この例では、入力パラメータaが10未満、100以上にならないことを前提としています。さらに、その結果の値がゼロ未満でないことが想定されます。 - 配列の範囲が、想定の範囲内に配置されている。
その配列が予想される範囲内に収まるかチェックするアサーション使用例void CMyClass::SomeMethod(const string &incomingArray[]) { //---配列境界のチェック assert(ArraySize(incomingArray)>0,"") assert(ArraySize(incomingArray)<=10,"") ... }
この例では、想定のincomingArray配列は、少なくとも一つの要素が含まれていますが、10を超えることができません。 - 作成されたオブジェクトの記述子が有効。
作成されたオブジェクトの記述子が有効であることを確認するためのアサーションの使用例void OnTick() { //---オブジェクト作成 CMyClass *a=new CMyClass(); //---一部のアクション ... ... ... //---存在するオブジェクトのチェック assert(CheckPointer(a),"") //--- 削除オブジェクト delete a; }
この例では、 OnTick実行の最後に、オブジェクト Aがまだ存在することを前提としています。 - 除数は除算演算でゼロに等しくしていますか?
ゼロの除数をチェックするためのアサーションの使用例void CMyClass::SomeMethod(const double a, const double b) { //---bが0でないかチェック assert(b!=0,"") //---bで割る double c=a/b; ... ... ... }
この例では、b で aを割っていますが、0に等しくないです。
アサーションを使用してチェックする条件には多くの種類があるのは確かですが、それぞれの場合で、絶対にユニークです。いくつかは、上に示されています。
事前条件と事後条件をチェックするためにアサーションを使用してください。 "コントラクトによる設計"と呼ばれるソフトウェアの設計と開発のためのアプローチがあります。このアプローチによれば、すべての関数、メソッドおよびクラスが前提条件と事後条件を使用してコントラクトにサインします。
前提条件は、メソッドやクラスメソッドを呼び出したり、オブジェクトのインスタンスを作成する前に実装します。言い換えれば、このメソッドが10を超える特定のパラメータを取るべき場合、プログラマは以下の値を渡すと保証するために、呼び出し元のコードを見る要があります。
事後条件は、メソッドやクラスが自身のタスクを終了する前に実装します。したがって、メソッドが100未満の値を返すべきではないと予想されるなら、プログラマは戻り値を見る必要があります。
事前条件と事後条件をドキュメント化し、また、プログラムの開発およびデバッグの段階で、その状況を監視することは非常に有効です。従来のコメントとは異なり、アサーションは絶えず監視します。事前条件と事後条件をチェックし、ドキュメント化するためのアサーションの使用例が「入力および出力メソッドの値をチェックするためのアサーションの使用例」にあるので、お読みください。
機会があれば、外部要因によって影響されないプログラミングエラーをチェックするためにアサーションを使用してみてください。 つまり、取引を開くときの有効性やクオートの履歴の確認には使わないことをお勧めします。ハンドルとエラーを記録することがより適切です。
アサーションで実行可能なコードを配置しないでください。。すべて、プログラムの最終バージョンのコンパイル段階で削除することができますので、プログラムの動作に影響を与えてはなりません。たとえば、この問題が頻繁にアサートの内部関数やメソッドを呼び出す際にリンクされています。
無効にした後でも、プログラムの動作に影響を与える可能性があるアサーション
void OnTick() { MyClass の someObject。 //---正しさのためにいくつかの計算をチェックする assert(someObject.IsSomeCalculationsAreCorrect(),"") ... ... ... }
このケースでは、アサーションの前に関数の呼び出しをする必要があり、特定の状態変数にその結果を保存し、アサーションでそれを確認してください。
すべてのアサーションを無効にした後、プログラムの動作に影響を与えることがないアサーション
void OnTick() { MyClass の someObject。 //---いくつかの計算をチェックします bool isSomeCalculationsAreCorrect = someObject.IsSomeCalculationsAreCorrect(); assert(isSomeCalculationsAreCorrect,"") ... ... ... }
エラーの取り扱いアサーションを混同しないでください。 アサーションは、開発時にプログラムのエラーを検索し、(プログラミングエラーの検索)デバッグするために使用されています。予想されるエラーの処理は、言い換えれば、プログラムのリリースバージョンの円滑な運営を可能にします。アサーション自体はエラーを処理できませんが、知らせてくれます。:「ねえ、ここにエラーがあるよ!」と。
たとえば、特定のクラスメソッドで引き渡されるべき値が10を超えるいなければいけない場合で、8が渡されたら、明らかにエラーであり、警告する必要があります。
入力パラメータが受け入れられない値を持つメソッドを呼び出す例(アサーションは、パラメータ値を確認するために使用されます)
void CMyClass::SomeMethod(const double a) { //--- 10を超えているかチェック assert(a>10,"") ... ... ... } void OnTick() { MyClass の someObject。 someObject.SomeMethod(8); ... ... ... }
さて、プログラマは値として8を渡すと、プログラムは知らせてくれます。:「値が10よりも下または10に等しいが、このメソッドでは転送することができません。」。
図2。入力パラメータが受け入れられない値を持つメソッドを呼び出す演算結果(アサーションは、パラメータ値を確認するために使用されています)
このようなメッセージを受け取った後、プログラマはすぐにエラーを修正することができます。
代わりに、プログラムの実行でヒストリーが1000本を超えて必要な場合、逆の状況がプログラマのミスとして考えられます。*1000本未満の足を処理するのがロジカルです。
必要な履歴が足りない場合の状況対処例(エラー処理は、このような状況で適用されます)
void OnTick() { if(Bars(Symbol(),Period())<1000) { Comment("プログラムが正しく動作するために不十分なヒストリー"); return; } }
最終版の安定性のため、アサーションを使用し、その後、エラーを処理してください。
アサーションとエラー処理の組み合わせの例
double CMyClass::SomeMethod(const double a) { //アサーションと入力パラメータのチェック値 assert(a>=10,"") assert(a<=100,"") //---入力パラメータのチェック double aValue = a; if(aValue<10) { aValue = 10; } else if(aValue>100) { aValue = 100; } //---結果の値を計算します double result=...; //---アサーションと結果の値をチェックします assert(result>=0,"") //---結果の値をチェックし、必要に応じて、それを修正 if(result<0) { result = 0; } return result; }
アサーションは、最終版のリリース前に、エラーを追跡するのに役立ちます。最終バージョンでのエラーを処理するときでさえ、開発とデバッグの段階で発見することができなかったエラーを見つけ、正しく動作することを可能にします。
(上記の例のように)エラーを処理する数々のメソッドがあります。それらのすべてを学ぶには、この記事の範囲を超えているでしょう。
また、プログラムが正しくクラッシュし、プログラマとの間でミスがあり、問題があることを示している場合、アサーションがこの場合には冗長性を有していることが、考えられています。たとえば、ゼロ除算でMQL5のプログラムがその実行を終了し、ログには関連するメッセージが表示されます。原理的には、このようなアプローチは、アサーションを行うよりも役立ちます。しかし、アサーションは、ソースコード内の古典的なコメントがより顕著になり、コードの前提条件についての情報などを追加することができ、それが大幅にさらに改善することができます。
結論
この記事では、アサーションのメカニズムを研究しMQL5での実装例を提供し、また、そのアプリケーションに関する一般的な推奨事項を提供してきました。正しく適用されたアサーションは大幅にソフトウェア開発およびデバッグ段階を簡素化することができます。
アサーションは、まずプログラミングエラーではなく、プログラマーに依存しない範囲をターゲットにしていることを覚えておいてください。アサーションはプログラムの最終版には含まれません。プログラマによらないエラーの場合は、エラー処理をするのが最適です。
アサーションメカニズムは密接にソフトウェアのテストの問題と関連しています。エラー処理とソフトウェアテストの両方が注目に値し、別の記事でカバーされる幅広い対象です。
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/1977
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索