객체 포인터

MQL5에서는 복잡한 유형 객체의 동적 생성이 가능합니다. 이것은 생성된 객체의 설명자를 반환하는 'new' 연산자를 사용하여 수행됩니다. 설명자의 사이즈는 8바이트입니다. MQL5의 객체 설명자는 구문적으로 C++ 포인터와 유사합니다.

예:

MyObject* hobject= new MyObject();

C++와 달리 위 예제의 'hobject' 변수는 메모리에 대한 포인터가 아니라 객체 설명자입니다. 또한 MQL5에서 함수에서 매개변수의 모든 객체는 참조로 전달되어야 합니다. 아래 예는 객체를 함수 매개변수로 전달하는 것을 보여줍니다:

class Foo
  {
public:
   string            m_name;
   int               m_id;
   static int        s_counter;
 //--- 생성자와 소멸자
                     Foo(void){Setup("noname");};
                     Foo(string name){Setup(name);};
                    ~Foo(void){};
   //--- Foo 객체 초기화
   void              Setup(string name)
     {
      m_name=name;
      s_counter++;
      m_id=s_counter;
     }
  };
int Foo::s_counter=0;
/+------------------------------------------------------------------+
//| 프로그램 시작 함수 스크립트                                        |
/+------------------------------------------------------------------+
void OnStart()
  {
//--- 자동 생성으로 객체를 변수로 선언
   Foo foo1;
//--- Transform passing object by reference
   PrintObject(foo1);
 
//--- 객체에 대한 포인터를 선언하고 'new' 연산자를 사용하여 생성
   Foo *foo2=new Foo("foo2");
//--- 참조로 객체에 대한 포인터를 전달하는 변형
   PrintObject(foo2); // 객체에 대한 포인터는 컴파일러에 의해 자동으로 변환됩니다
 
//--- Foo 객체의 배열 선언
   Foo foo_objects[5];
//--- 객체 배열 전달의 변형
   PrintObjectsArray(foo_objects); // 객체 배열을 전달하기 위한 별도의 함수
 
//--- Foo 유형의 객체에 대한 포인터 배열 선언
   Foo *foo_pointers[5];
   for(int i=0;i<5;i++)
      foo_pointers[i]=new Foo("foo_pointer");
//--- 포인터의 배열 전달의 변형
   PrintPointersArray(foo_pointers); // 포인터 배열을 전달하기 위한 별도의 함수
 
//--- 완료하기 전에 포인터로 생성된 객체를 삭제해야 합니다
   delete(foo2);
//--- 포인터의 배열을 제거
   int size=ArraySize(foo_pointers);
   for(int i=0;i<5;i++)
      delete(foo_pointers[i]);
//---   
  }
/+------------------------------------------------------------------+
//|  객체는 항상 참조로 전달됩니다.                                     |
/+------------------------------------------------------------------+
void PrintObject(Foo &object)
  {
   Print(__FUNCTION__,": ",object.m_id," Object name=",object.m_name);
  }
/+------------------------------------------------------------------+
//| 객체의 배열을 전달                                                 |
/+------------------------------------------------------------------+
void PrintObjectsArray(Foo &objects[])
  {
   int size=ArraySize(objects);
   for(int i=0;i<size;i++)
      PrintObject(objects[i]);
  }
/+------------------------------------------------------------------+
//| 객체 포인터의 배열을 전달                                          |
/+------------------------------------------------------------------+
void PrintPointersArray(Foo* &objects[])
  {
   int size=ArraySize(objects);
   for(int i=0;i<size;i++)
      PrintObject(objects[i]);
  }
/+------------------------------------------------------------------+

 

사용하기 전에 포인터를 체크하세요

잘못된 포인터에 액세스하려는 시도는 프로그램의 치명적 종료로 이어집니다. CheckPointer 함수는 포인터를 사용하기 전에 확인하는 기능입니다. 포인터는 다음과 같은 경우에 유효하지 않을 수 있습니다:

  • 포인터가 NULL; 일때
  • 객체가 delete 연산자를 사용하여 제거 되었을 때

이 함수는 포인터의 유효성을 검사하는 데 사용될 수 있습니다. 0이 아닌 값은 이 포인터에서 데이터에 액세스할 수 있음을 나타냅니다.

class CMyObject
 {
protected:
  double             m_value;
public:
                     CMyObject(void);
                     CMyObject(double value) {m_value=value;};
                    ~CMyObject(void){};
  //---
  double             Value(void) {return(m_value);}
 };
/+------------------------------------------------------------------+
//| 프로그램 시작 함수 스크립트                                         |
/+------------------------------------------------------------------+
void OnStart()
 {
//--- 초기화되지 않은 객체 생성
  CMyObject *pointer;
  if(CheckPointer(pointer)==POINTER_INVALID)
    Print("1. pointer is "EnumToString(CheckPointer(pointer)));
  else
    Print("1. pointer.Value()="pointer.Value());
 
//--- 포인터 초기화
  pointer=new CMyObject(M_PI);
  if(CheckPointer(pointer)==POINTER_INVALID)
    Print("2. pointer is "EnumToString(CheckPointer(pointer)));
  else
    Print("2. pointer.Value()="pointer.Value());
 
//--- 객체를 삭제
  delete(pointer);
  if(CheckPointer(pointer)==POINTER_INVALID)
    Print("3. pointer is "EnumToString(CheckPointer(pointer)));
  else
    Print("3. pointer.Value()="pointer.Value());
 }
/*
   1pointer is POINTER_INVALID
   2pointer.Value()=3.141592653589793
   3pointer is POINTER_INVALID
*/

포인터의 유효성을 빠르게 확인하려면 "!" 연산자를 사용할 수도 있습니다. (LNOT) CheckPointer 함수의 묵시적 호출을 통해 이를 확인합니다. 이는 좀더 깔끔하고 간략한 코드 작성을 가능하게 합니다. 아래는 이전 예에서 체크한 것입니다:

/+------------------------------------------------------------------+
//| 프로그램 시작 함수 스크립트                                        |
/+------------------------------------------------------------------+
void OnStart()
 {
//--- 초기화되지 않은 객체 생성
  CMyObject *pointer;
  if(!pointer)
    Print("1. pointer is "EnumToString(CheckPointer(pointer)));
  else
    Print("1. pointer.Value()="pointer.Value());
 
//--- 포인터 초기화
  pointer=new CMyObject(M_PI);
  if(!pointer)
    Print("2. pointer is "EnumToString(CheckPointer(pointer)));
  else
    Print("2. pointer.Value()="pointer.Value());
 
//--- 객체를 삭제
  delete(pointer);
  if(!pointer)
    Print("3. pointer is "EnumToString(CheckPointer(pointer)));
  else
    Print("3. pointer.Value()="pointer.Value());
 }
/*
   1pointer is POINTER_INVALID
   2pointer.Value()=3.141592653589793
   3pointer is POINTER_INVALID
*/

연산자 "=="는 NULL을 빠르게 확인하는 데 사용됩니다. 일례: ptr==NULL 혹은 ptr!=NULL.

더 보기

변수, 변수 초기화, 가시성 범위 및 변수 수명, 객체 생성 및 삭제