Last active
February 12, 2021 10:42
-
-
Save hidsh/3f4a0d0e205c7b13eb43e8e3e6a5305e to your computer and use it in GitHub Desktop.
MQL4では参照を返せないっぽいので、ポインタを返すテストプログラム。fixできるが、再発防止という点でイマイチ。他にいいやり方はないのか。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//+------------------------------------------------------------------+ | |
//| obj-pointer-test-bugggggg.mq4 | | |
// バグっているコード。 | |
// 参照のつもりでコンテナ内のメンバ変数を書き換えようとしても、書き換えたのは参照先ではなくコピーしたオブジェクトのほうなので、 | |
// メンバ変数は書き換えできない。--> 32行目付近 | |
//+------------------------------------------------------------------+ | |
#property strict | |
class TObj { | |
int m_; | |
public: | |
TObj() :m_(0) {} | |
TObj(const TObj& o) :m_(o.m_) {Print("コピーコンストラクタ");} | |
int get_m() {return m_;} | |
void set_m(int val) {m_ = val;} | |
}; | |
class TCont { | |
TObj arr[1]; | |
public: | |
TCont() {arr[0] = TObj();} | |
TObj peep() {return arr[0];} | |
}; | |
//+------------------------------------------------------------------+ | |
//| Script program start function | | |
//+------------------------------------------------------------------+ | |
TCont cont; | |
void OnStart() | |
{ | |
TObj o = cont.peep(); | |
printf("o.get_m: %d cont.peep().get_m(): %d", o.get_m(), cont.peep().get_m()); | |
o.set_m(99); // バグ!! 参照のつもりで元の値を変更しようとしている | |
printf("o.get_m: %d cont.peep().get_m(): %d", o.get_m(), cont.peep().get_m()); | |
/* | |
o.get_m: 99 cont.peep().get_m(): 0 // 2回目 TObjのコピーのメンバに代入しているだけなので、元の配列内のTObjは変更されない | |
コピーコンストラクタ // コピーコンストラクタが呼ばれているので参照ではなく、新しい実体にメンバをコピーしている | |
o.get_m: 0 cont.peep().get_m(): 0 // 初回 | |
*/ | |
} | |
//+------------------------------------------------------------------+ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//+------------------------------------------------------------------+ | |
//| obj-pointer-test-fixed.mq4 | | |
// | |
// 一応直したコード。 | |
// だが、以下2点の問題があるので、ポインタ変数宣言時にうっかり "*" をつけ忘れただけでですぐバグる危険がある。 | |
// | |
// 1. MQLでは参照を(引数には渡せるが、)返り値として返すことができないので、返すときはGetPoiinter()でポインタを使う必要がある。--> 29行目 | |
// 2. コンパイラが型チェックをしないので、オブジェクト型の変数にポインタが代入できてしまう--> 49行目(コピーコンストラクタでコピーを作る)→ やはりバグる。 | |
// 3. コピーコンストラクタを無効にするためにprivateにすると、コンパイルできない。--> 16行目(コピーコンストラクタを明示的に書かないと自動的に作られて、1と同じ結果になる) | |
// | |
//+------------------------------------------------------------------+ | |
#property strict | |
class TObj { | |
int m_; | |
// TObj(const TObj& o) :m_(o.m_) {} // コピーコンストラクタをprivateにして無効化しようとすると、コンパイルエラーが出る。"TObj::TObj' - cannot access private member function" | |
public: | |
TObj() :m_(0) {} | |
TObj(const TObj& o) :m_(o.m_) {Print("警告!コピーコンストラクタは危ないので使用禁止!");} // MQLでは、コピーコンストラクタをprivateにすることでコピーコンストラクタを無効化することもできないので、とりあえずエラーログを吐かすしかないか。 | |
int get_m() {return m_;} | |
void set_m(int val) {m_ = val;} | |
}; | |
class TCont { | |
TObj arr[1]; | |
public: | |
TCont() {arr[0] = TObj();} | |
// TObj& peep() {return arr[0];} // 参照を返そうとすると、コンパイルエラーになる "'&' - reference cannot used" | |
TObj* peep() {return GetPointer(arr[0]);} // <-- しかたないので、ポインタを返す | |
}; | |
//+------------------------------------------------------------------+ | |
//| Script program start function | | |
//+------------------------------------------------------------------+ | |
TCont cont; | |
void OnStart() | |
{ | |
TObj* po = cont.peep(); // ポインタの代入なので、コピーコンストラクタは使われない | |
printf("po.get_m: %d cont.peep().get_m(): %d", po.get_m(), cont.peep().get_m()); | |
po.set_m(99); | |
printf("po.get_m: %d cont.peep().get_m(): %d", po.get_m(), cont.peep().get_m()); | |
/* | |
po.get_m: 99 cont.peep().get_m(): 99 // 2回目 意図通り、元の配列内のTObjが変更されている。 | |
po.get_m: 0 cont.peep().get_m(): 0 // 初回 この行の次の行に「コピーコンストラクタ」と出力されていないので、コピーコンストラクタが呼ばれていないことがわかる | |
*/ | |
TObj o = cont.peep(); // これはTObj型の変数にポインタを代入しているが、MQLではコンパイルエラーにならない(当然C++では型チェックでコンパイルエラーになる) | |
o.set_m(1111); // で、しれっとバグるので注意! | |
printf("o.get_m: %d cont.peep().get_m(): %d", o.get_m(), cont.peep().get_m()); | |
/* | |
o.get_m: 1111 cont.peep().get_m(): 99 // やっぱりバグる!! | |
*/ | |
} | |
//+------------------------------------------------------------------+ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//+------------------------------------------------------------------+ | |
//| obj-pointer-test.cpp | | |
// ちなみに、C++ でどうなるかやってみたコード。やはりコンパイルエラーになる --> 40行目 | |
//+------------------------------------------------------------------+ | |
// #property strict | |
#include <stdio.h> | |
#define Print printf | |
class TObj { | |
int m_; | |
public: | |
TObj() :m_(0) {} | |
TObj(const TObj& o) :m_(o.m_) {Print("コピーコンストラクタ");} | |
int get_m() {return m_;} | |
void set_m(int val) {m_ = val;} | |
}; | |
class TCont { | |
TObj arr[1]; | |
public: | |
TCont() {arr[0] = TObj();} | |
TObj* peep() {return &arr[0];} // <-- ポインタを返す (C++) | |
}; | |
//+------------------------------------------------------------------+ | |
//| Script program start function | | |
//+------------------------------------------------------------------+ | |
TCont cont; | |
void OnStart() | |
{ | |
TObj* po = cont.peep(); // ポインタの代入なので、コピーコンストラクタは使われない | |
printf("po->get_m: %d cont.peep().get_m(): %d", po->get_m(), cont.peep()->get_m()); | |
po->set_m(99); | |
printf("po->get_m: %d cont.peep()->get_m(): %d", po->get_m(), cont.peep()->get_m()); | |
/* | |
*/ | |
TObj o = cont.peep(); // <-- g++ では当然エラー "error: conversion from ‘TObj*’ to non-scalar type ‘TObj’ requested" | |
o.set_m(1111); | |
printf("o.get_m: %d cont.peep().get_m(): %d", o.get_m(), cont.peep().get_m()); | |
} | |
//+------------------------------------------------------------------+ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//+------------------------------------------------------------------+ | |
//| obj-pointer-test-mq5.mq5 | | |
// ちなみに、MQL5 でどうなるかやってみたコード。MQL4とまったく同じ動作で同じくバグる。希望なし。MQL6はまだか。 | |
//+------------------------------------------------------------------+ | |
class TObj { | |
int m_; | |
public: | |
TObj() :m_(0) {} | |
TObj(const TObj& o) :m_(o.m_) {Print("警告!コピーコンストラクタは危ないので使用禁止!");} // MQLでは、コピーコンストラクタをprivateにすることでコピーコンストラクタを無効化することもできないので、とりあえずエラーログを吐かすしかないか。 | |
int get_m() {return m_;} | |
void set_m(int val) {m_ = val;} | |
}; | |
class TCont { | |
TObj arr[1]; | |
public: | |
TCont() {arr[0] = TObj();} | |
TObj* peep() {return GetPointer(arr[0]);} // <-- ポインタを返す (MQLでは参照を返せないので、ポインタを使う) | |
}; | |
//+------------------------------------------------------------------+ | |
//| Script program start function | | |
//+------------------------------------------------------------------+ | |
TCont cont; | |
void OnStart() | |
{ | |
TObj* po = cont.peep(); // ポインタの代入なので、コピーコンストラクタは使われない | |
printf("po.get_m: %d cont.peep().get_m(): %d", po.get_m(), cont.peep().get_m()); | |
po.set_m(99); | |
printf("po.get_m: %d cont.peep().get_m(): %d", po.get_m(), cont.peep().get_m()); | |
/* | |
po.get_m: 99 cont.peep().get_m(): 99 // 2回目 意図通り、元の配列内のTObjが変更されている。 | |
po.get_m: 0 cont.peep().get_m(): 0 // 初回 この行の次の行に「コピーコンストラクタ」と出力されていないので、コピーコンストラクタが呼ばれていないことがわかる | |
*/ | |
TObj o = cont.peep(); // これはTObj型の変数にポインタを代入しているが、MQLではコンパイルエラーにならない(当然C++ではコンパイルエラーになる) | |
o.set_m(1111); // で、しれっとバグるので注意! | |
printf("o.get_m: %d cont.peep().get_m(): %d", o.get_m(), cont.peep().get_m()); | |
/* | |
o.get_m: 1111 cont.peep().get_m(): 99 // やっぱりバグる!! | |
*/ | |
} | |
//+------------------------------------------------------------------+ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment