일반 클래스 라이브러리 - 버그, 설명, 질문, 사용 기능 및 제안 사항 - 페이지 26

 
Andrey Pogoreltsev :

new를 통해 AddValue에서 개체의 복사본을 만들지만 소멸자에서 개체를 해제하지 않고 포인터 목록을 지우면 됩니다.

도움말에 따르면 소멸자가 호출되면 사용된 클래스의 소멸자도 호출됩니다.

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

터미널이 스크립트를 언로드한 후 로그에 파괴되지 않은 개체에 대한 경고를 기록하지 않은 경우를 기억하지 못합니다. 제 예제에는 그러한 경고가 표시되지 않습니다.


안드레이 포고렐체프 :

둘째, 올바른 것에 따르면 할당 연산자가 아닌 복사 생성자를 통해 수행해야했습니다. 하지만 그게 다야 IMHO)

개발자들에 따르면 MQL의 간단한 구조나 클래스는 항상 문제 없이 복사된다는 정보를 발견했고, 여러 번 확인했는데 언어 기능을 사용하면서 그렇게 된 것 같습니다.


일반적으로 여기에서 전체 토론은 무엇입니까 - MQL은 C ++가 아닙니다. 오래전에 그들 사이의 유추를 찾는 것을 중단했습니다. 개발자는 이것이 다음과 같이 구현되었다고 썼습니다. 확인했습니다. 작동합니다. 사용할 수 있습니다. 표준 C++ 구문을 갖는 것이 중요한 경우 .dll의 모든 논리를 꺼내는 것은 어렵지 않습니다.

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

new를 통해 AddValue에서 개체의 복사본을 만들지만 소멸자에서 개체를 해제하지 않고 포인터 목록을 지우면 됩니다.

젠장! 그리고 소멸자에서 new를 통해 생성된 클래스의 인스턴스를 어떻게 삭제할 수 있습니까? 시도 해봐. 작동하지 않을 것입니다.

다른 클래스의 소멸자에서만 이 작업을 수행할 수 있습니다.

 
Nikolai Semko :

젠장! 그리고 소멸자에서 new를 통해 생성된 클래스의 인스턴스를 어떻게 삭제할 수 있습니까? 시도 해봐. 작동하지 않을 것입니다.

다른 클래스의 소멸자에서만 이 작업을 수행할 수 있습니다.

그것은 다른 클래스의 소멸자에 관한 것이었습니다. AddValue 메서드에서 new를 통해 생성된 요소에 대해 이야기하고 있었습니다.

 
Igor Makanu :

도움말에 따르면 소멸자가 호출되면 사용된 클래스의 소멸자도 호출됩니다.

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

터미널이 스크립트를 언로드한 후 로그에 파괴되지 않은 개체에 대한 경고를 기록하지 않은 경우를 기억하지 못합니다. 제 예제에는 그러한 경고가 표시되지 않습니다.


개발자들에 따르면 MQL의 간단한 구조나 클래스는 항상 문제 없이 복사된다는 정보를 발견했고, 여러 번 확인했는데 언어 기능을 사용하면서 그렇게 된 것 같습니다.


일반적으로 여기에서 전체 토론은 무엇입니까 - MQL은 C ++가 아닙니다. 오래전에 그들 사이의 유추를 찾는 것을 중단했습니다. 개발자는 이것이 다음과 같이 구현되었다고 썼습니다. 확인했습니다. 작동합니다. 사용할 수 있습니다. 표준 C++ 구문을 갖는 것이 중요한 경우 .dll의 모든 논리를 꺼내는 것은 어렵지 않습니다.

예, 도움말에서 봤습니다... 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);
}

포인터를 저장하려면 unique_ntr 래퍼를 작성하세요(완전한 래퍼는 작동하지 않지만 auto_ntr 이상). 제 생각에는 그러한 프리미티브조차도 std의 템플릿 유사체보다 훨씬 편리합니다.