汎用クラスライブラリ - バグ、説明、質問、使用上の特徴、提案 - ページ 26

 
Andrey Pogoreltsev:

AddValueではnewでオブジェクトのコピーを作成しますが、デストラクタでそれを解放せず、ポインタのリストをクリアするだけです。

ヘルプによると、デストラクタを呼び出すと、使用したクラスのデストラクタもまた

https://www.mql5.com/ru/docs/standardlibrary/datastructures/carrayobj#carrayobjfeatures

スクリプトがアンロードされた後、破壊されていないオブジェクトに関する警告をターミナルがログに書き込まなかったケースを覚えていません。


アンドレイ・ポゴレルツェフ

次に、代入演算子ではなく、コピーコンストラクタで正しく行うべきでした。しかし、これはすべてIMHOです)

MQLの単純な構造体やクラスは必ず問題なくコピーされるという開発者の情報を見つけ、何度か確認しましたが、言語機能を使う限りはその通りのようです


MQLはC++ではない、両者の類似性を探すのはやめた、開発者はこう実装している、確認した、動く、だから使っていい、と書いている。

Документация по MQL5: Стандартная библиотека / Коллекции данных / CArrayObj
Документация по MQL5: Стандартная библиотека / Коллекции данных / CArrayObj
  • www.mql5.com
Класс CArrayObj обеспечивает возможность работы с динамическим массивом указателей на экземпляры класса CObject и его наследников. Это дает возможность работы как с многомерными динамическими массивами примитивных типов данных, так и с более сложно организованными структурами данных. В классе реализованы возможности добавления/вставки/удаления...
 
Andrey Pogoreltsev:

AddValueではnewでオブジェクトのコピーを作成しますが、デストラクタではそれらを解放せず、ポインタリストをクリアするだけです。

あら、そうなの!?また、デストラクタのnewで生成されたクラスのインスタンスを削除するにはどうすればよいのでしょうか?してみてください。うまくいきません。

他のクラスのデストラクタの中でしかできません。

 
Nikolai Semko:

やばい!また、デストラクタのnewで生成されたクラスのインスタンスを削除するにはどうすればよいのでしょうか?試してみてはいかがでしょうか。うまくいきません。

他のクラスのデストラクタでのみ可能です。

別クラスのデストラクタの話でした。AddValue メソッドでnewして作成されたアイテムについて述べています。

 
Igor Makanu:

ヘルプによると、デストラクタが呼ばれたときに、使用されたクラスのデストラクタも

https://www.mql5.com/ru/docs/standardlibrary/datastructures/carrayobj#carrayobjfeatures

スクリプトがアンロードされた後、ターミナルが破壊されていないオブジェクトについての警告をログに書き込まなかったケースを覚えていません。


開発者から、MQLの単純な構造体やクラスは常に問題なくコピーされると聞き、何度か確認したところ、どうやら本当のようです。


MQLはC++ではありません。私は両者の類似性を探すのをやめました。開発者は、これが実装方法であると書いています。

はい、ヘルプで見ました...。非常に暗黙的なもので、unique_ptrの代わりに松葉杖のように見えますが...。

 
Andrey Pogoreltsev:

はい......ヘルプで見ました......。非常に暗黙的なもので、unique_ptrの代わりに松葉杖のようなもの...。

しかも、松葉杖とは呼べないほど便利なんです。

任意のクラスのオブジェクトを作成し、ストレージリストに入れれば、もうそれを削除する心配はありません - ターミナルサブシステムが勝手に掃除してくれます。
しかし、いつ、どこで、どのような目的で作成されたのか、今必要なのかを追跡しようと、新しく作成されたすべてのオブジェクトに対して手動操作と「実行」を設定することも可能です。不要な場合は、削除してください。しかし、間違えてしまった時に、それが必要だったことが判明する。無効なポインタにアクセスするとクラッシュする...。

つまり、松葉杖は、役に立たないものを探して「オブジェクトを追いかける」だけで、どこかのオブジェクトが追いついていないとメモリーリークを心配することになります。

 
Andrey Pogoreltsev:

次に、正しい方法は、代入演算子の代わりにコピーコンストラクタを使用することです。ただし、これはすべてIMHO)

このテンプレートに正しくコピーするための例を教えてください。

template<typename T>class CDataBase
  {
private:
   CList            *mlist;
   T                *Tptr;
public:
   void CDataBase()           { mlist=new CList;                                       }
   void ~CDataBase(void)      { delete mlist;                                          }
   int ArraySize(void)        { return(mlist.Total());                                 }
   T *operator[](int index)   { return(mlist.GetNodeAtIndex(index));                   }
   void  AddValue (T &value)  { Tptr = new T; Tptr  = value; mlist.Add(Tptr);          }
   string TypeName()          { return(typename(T));                                   }
  };

AddValueメソッドの記述にヘルプを使用しましたhttps://www.mql5.com/ru/docs/basis/types/classes

頭を悩ませましたが、MQLには例題に書いたような解決策しか見当たりません

正しいデータ保存の実装を見せてください

Документация по MQL5: Основы языка / Типы данных / Структуры, классы и интерфейсы
Документация по MQL5: Основы языка / Типы данных / Структуры, классы и интерфейсы
  • www.mql5.com
Структура является набором элементов произвольного типа (кроме типа void). Таким образом, структура объединяет логически связанные данные разных типов. Объявление структуры Имя структуры нельзя использовать в качестве идентификатора (имени переменной или функции). Следует иметь ввиду, что в MQL5 элементы структуры следуют непосредственно друг...
 
Artyom Trishkin:

しかも、松葉杖とは呼べないほど便利なんです。

どのようなクラスのオブジェクトでも作成し、ストレージリストに入れれば、もう削除する心配はない。ターミナルサブシステムが勝手に掃除してくれる。
しかし、手動操作を設定し、新しく作成されたすべてのオブジェクトに対して、いつ、どこで、どのような目的で作成されたのか、今必要なのかどうかを調べるために「実行」することも可能です。不要な場合は、削除してください。しかし、間違えてしまった時に、それが必要だったことが判明する。無効なポインタにアクセスするとクラッシュする...。

つまり、松葉杖は、役に立たないものを探して「オブジェクトを追いかける」だけで、どこかのオブジェクトが追いついていないとメモリーリークを心配することになります。

ここで言いたいのは、コレクションにポインタを追加すると、そのポインタも一緒に残ってしまうということです。これが第一のポイントです。

第二に、アレイコレクションや連続読み出しの話ではなく、断片的なシステムになっていることです。

第三に、コレクションオブジェクトへのポインタを渡したかどうかが保証されない。
 
Andrey Pogoreltsev:
ここでのポイントは、一度コレクションにポインタを追加すると、そのポインタも一緒に残るということです。それがまず第一です。

第二に、アレイコレクションや連続読み出しの話ではなく、断片的なシステムを持っていることです。

第三に、コレクション・オブジェクトへのポインタを渡したことを誰も保証してくれない。
  1. 自分が作ったオブジェクトをターミナルサブシステムが自動的に削除してリストにポインタを置くことを松葉杖と呼ぶのであって、自分のオブジェクトを手動で操作してそのための松葉杖を作ることを松葉杖とは思わないという意味です。
  2. それは、1.でおっしゃったこととは別で、私が返答した最大の理由です。
  3. それも、同じ理由で。
 
Igor Makanu:

ヘルプによると、デストラクタが呼ばれたときに、使用されているクラスのデストラクタも呼ばれます

https://www.mql5.com/ru/docs/standardlibrary/datastructures/carrayobj#carrayobjfeatures

スクリプトがアンロードされた後、ターミナルが破壊されていないオブジェクトについての警告をログに書き込まなかったケースを覚えていません。


開発者から、MQLの単純な構造体やクラスは常に問題なくコピーされると聞き、何度か確認したところ、どうやら本当のようです。


MQLはC++ではありません。両者の類似性を探すのはあきらめました。開発者は、このように実装されていると書きました。私はそれを確認し、動作しました。ですから、標準のC++構文が重要であれば、.dllで簡単にすべての論理を記述して使用できます

これで三角形のアレイが作れるのか?

 

言語の制限もあり、まともなものが動くとは思えません。私はこの松葉杖(標準的な配列の上の軽量ラッパー)を持っています。

#define  GENERATE_VECTOR_GROWTH_FACTOR 2
#define  GENERATE_VECTOR(NAME, REF)                                         \  
   template <typename T>                                                   \
   class NAME                                                              \
   {                                                                       \
      int sz;                                                              \
      bool fail_state;                                                     \
   public:                                                                 \
      T a[];                                                               \
      NAME(): sz(0), fail_state(false) {}                                  \
      bool operator!()const      {return this.fail_state;}                 \
      uint size()const           {return this.sz;}                         \
      void clear()               {this.sz = 0; this.fail_state = false;}   \
      void push_back(T REF value) {                                        \
         if (this.sz == ArraySize(this.a)  &&                              \
             ArrayResize(this.a, this.sz*                                  \
                           GENERATE_VECTOR_GROWTH_FACTOR+1) == -1) {       \
            this.fail_state = true;                                        \
            return;                                                        \
         }                                                                 \
         this.a[this.sz++] = value;                                        \
      }                                                                    \
      void reserve(int new_cap) {                                          \
         if (new_cap > ArraySize(this.a))                                  \
            ArrayResize(this.a, new_cap);                                  \
      }                                                                    \
      void erase(int pos) {                                                \
         if ( ! ArrayRemove(this.a, pos, 1) )                              \
            this.fail_state = true;                                        \
      }                                                                    \
   };
#define  GENERATE_VECTOR_EMPTY
GENERATE_VECTOR(vector_fund, GENERATE_VECTOR_EMPTY);  // для фундаментальных типов
GENERATE_VECTOR(vector_ref, const &);                 // для пользовательских
#undef  GENERATE_VECTOR_EMPTY
#undef  GENERATE_VECTOR_GROWTH_FACTOR

struct S {int a;};
class Q {};
bool f() {
   vector_ref<S> v1;
   vector_fund<int> v2;
   vector_ref<Q> v3;
   
   Q q;
   v3.push_back(q);
   v2.push_back(3);
   v2.a[0] = 5;
   
   return !(!v1 || !v2 || !v3);
}

ポインタを格納するには、unic_ptrのラッパーを書きます(本格的なものは無理ですが、最低でもauto_ptr)。私見では、このプリミティブでも、stdのテンプレート対応よりずっと便利だと思います。