Указатели и объекты. Кто есть кто и как их использовать?

 

Не понимаю разницу между:

M oM=M();

M* uM=new M();

Из принципов - указатели нужны для того. Что бы использовать конструктор с аргументами. И что бы функции их возвращала. Т.е. по сути всегда выгоднее.

Но с указателями много ошибок связанных отсутствием самого объекта указываемого, что приводит к исключению (а это плохо). И сложности с его удалением, если они создаются и линкуются в библиотеках (остаются копии). 

Сложно сказать почему. Использую List библиотечный в своих библиотеках

Вернуть объект из функции можно. Но если есть конструктор копии. И с ним что то непонятно:

class M
  {
public :
   int               i;
   int               j;
                     M(int I, int J)
     {
      i=I;
      j=J;
     }
                     M(const M&)
     {
      i=2;
      j=3;
     }
  };

Создать объект можно так 

 M m1=M(1,1);

Но запущен будет именно конструктор копии. Если же его нет, появится ошибка. А вот указателем проблем не будет. Странный подход.

Конструктор копии изначально запрещает изменять объект. Бесполезный объект получается. Может, я что то не знаю? И можно как то использовать сами объекты?

M BackObject()
  {
   M o= M(3,2);
   o.i=5;
   return o;
  }
M m1=M(1,1);  
M m2=BackObject();
Print("M1="+m1.i);
Print( "M2="+m2.i);

Во всех случаях i=2 Что в конструкторе копии.

 

У вас видимо, путаница с терминологией что такое обьект, а что такое указатель. Про обьекты, указатели и ссылки предварительно почитайте касаемо C++, станет намного понятнее. 

В вашем случае:

M m1(3,2);

Обьект m1 создается на стеке. Под стек фиксированый кусок памяти выделяется заранее, при запуске программы. Память под обьект выделяется практически мнгновенно путем перемещения указателя стека и удаляется при выходе за область видимости, путем возврата указателя стека на прежнее место. Такой способ во первых в разы экономит время на создание обьекта, во вторых не требует контроля освобождения памяти, так как оно происходит автоматически исходя из принципа работы стека.

M* m1 = new M(3,2);

Создание объекта происходит на куче (она же динамическая память). Эта память является общесистемной и перед созданием обьекта, идет запрос в систему на выделение памяти, далее система ищет непрерывный кусок памяти под размер обьекта, возвращает указатель на область выделенной памяти и только после этого, ваша программа в этой выделенной памяти создает обьект. Так же, в этом случае, вы сами должны следить за тем, когда обьект вам более не нужен и вызывать delete что бы вызвать деструктор обьекта освободить выделеную память. Если же этого не сделать и скажем, в цикле наплодить кучу обьектов не удалив их - появятся так называемые, утечки памяти и ваш эксперт может занять всю свободную память в системе и она будет освобождена только после завершения процесса. А так как эксперты атачатся обычно либо к самому терминалу либо к агентам - то это может произойти только после перезапуска терминала или агента.

Кроме этого, в более или менее сложном коде, вы будете натыкаться на:

M* m1 = NULL;
....
if (.....)
  m1 = new M1(1,1);

Print(m1.j);

или

M* m1 = new M(1,1);

.....
delete m1;
.....
Print(m1.j);

Оба этих варианта вызовут краш советника.

M m1=M(1,1); 

Не носит абсолютно никакой нагрузки. В данном случае, вы обьявляете на стеке обьект m1, создаете еще один временный обьект через M(1, 1) копируете временный обьект в m1. Компилятор скорее всего все равно приведет это к виду M m1(1, 1);

Резюмируя - всегда, когда возможно, вы должны стараться создавать обьекты и переменные на стеке. Это сильно быстрее и избавляет от необходимости контроля удаления обьекта.

Если же говорить об указателях в аргументах функций - то там в качестве указателя, вы можете передать как указатель на обьект в стеке, так и указатель на обьект в куче.

M m1(1, 1);
M* m2 = new M(1, 1);

void print_m(const M* m)
{
  Print(m.j);
}

print_m(&m1); // Correct
print_m(m2); // Correct
Еще раз. Для передачи параметров в конструктор, никакие указатели с new или конструкторы копирования не нужны. Достаточно M m1(1, 1). Конструктор копирования нужен только тогда, когда вы делаете
M m1(1, 1);
....
M m2(2, 2);
.....
m1 = m2;
И то, в большинстве случаев, компилятор сам может создать конструктор копирования по умолчанию, так что ничего писать не нужно. И только если у вас сложный обьект - компилятор вас об этом попросит. Только в этом случае, имеет смысл что то создавать.
 
vbymrf:

...

Из принципов - указатели нужны для того. Что бы использовать конструктор с аргументами. И что бы функции их возвращала. Т.е. по сути всегда выгоднее.

...

Не, указатели нужны не для этого.

Основной принцип - если что-то можно сделать без указателей, то надо делать без указателей.  

 
Dmitry Fedoseev #:

Не, указатели нужны не для этого.

Основной принцип - если что-то можно сделать без указателей, то надо делать без указателей.  

Лучше наоборот - если можно без & то точно без них (кстати и без const тоже, про него отдельно) :-) 

и если захотелось сделать конструктор копирования - то нужно писать большую пояснительную записку

возможно вы просто в указатели не умеете 

 
Maxim Kuznetsov #:

Лучше наоборот - если можно без & то точно без них (кстати и без const тоже, про него отдельно) :-) 

и если захотелось сделать конструктор копирования - то нужно писать большую пояснительную записку

возможно вы просто в указатели не умеете 

Как можно так сильно бредить? Имелось ввиду автоматическое и динамическое создание объектов.

Так вот, если для решения задачи достаточно автоматического создания объектов, то и надо использовать только автоматическое создание.

Не, ну если, вам хочется непрерывно чувствовать себя настоящим яжпрограммистом... а всех остальных лохами... только new - и никак иначе - с этим не поспоришь.

 

И мои 5 копеек. Тут посоветовали изучать указатели по С++. Но надо помнить, что в MQL4/5 нет нативных указателей, как в плюсах. В С++ указатель реально содержит адрес памяти, по которому размещен объект. Причем, если пойнтер содержит адрес, к примеру 123456, а на компе 8 Гб ОЗУ, это не значит, что 123456 это физический адрес в ОЗУ, каждому процессу Винда выделяет свой блок виртуальной памяти, который вполне может быть физически сегментирован, но иметь виртуальную линейную адресацию.

А в MQL дескрипторы объектов Метаквоты в приступе важности обозвали указателями, хотя все сходство только в синтаксисе. То есть нет арифметики указателей, как в плюсах, нельзя сделать дескриптор на простой тип данных. Это должна знать каждая кухарка, тогда она сможет управлять MQL )).            

   

 
Alexey Volchanskiy #:

А в MQL дескрипторы объектов Метаквоты в приступе важности обозвали указателями, хотя все сходство только в синтаксисе. То есть нет арифметики указателей, как в плюсах, нельзя сделать дескриптор на простой тип данных. Это должна знать каждая кухарка, тогда она сможет управлять MQL )).            

Назвать указателем и при этом не сделать хотя бы равнозначным обращения (1) и (2)

class A {
public:
        int a;
};
void OnStart()
{
        A *a = new A;
        Print( a. a ); //(1)
        Print( a->a ); //(2)
}

это как минимум не логично

 

Использую массив "указателей" на базовый класс, а лежат там "указатели" на объекты производных.

Каждый объект - отдельный робот со своей логикой, параметрами, логом и стейтом.

Но я не программист.

 
JRandomTrader #:

Использую массив "указателей" на базовый класс, а лежат там "указатели" на объекты производных.

Каждый объект - отдельный робот со своей логикой, параметрами, логом и стейтом.

Но я не программист.

В этом и смысл.

 
Alexey Volchanskiy #:

И мои 5 копеек. Тут посоветовали изучать указатели по С++. Но надо помнить, что в MQL4/5 нет нативных указателей, как в плюсах. В С++ указатель реально содержит адрес памяти, по которому размещен объект. Причем, если пойнтер содержит адрес, к примеру 123456, а на компе 8 Гб ОЗУ, это не значит, что 123456 это физический адрес в ОЗУ, каждому процессу Винда выделяет свой блок виртуальной памяти, который вполне может быть физически сегментирован, но иметь виртуальную линейную адресацию.

А в MQL дескрипторы объектов Метаквоты в приступе важности обозвали указателями, хотя все сходство только в синтаксисе. То есть нет арифметики указателей, как в плюсах, нельзя сделать дескриптор на простой тип данных. Это должна знать каждая кухарка, тогда она сможет управлять MQL )).            

   

Для понимания этого вполне достаточно. Какую арифметику указателей вы собрались применять, для чего и самое главное, как она позволяет "управлять" MQL? А по поводу указателей и адресов памяти - string& в dll замечательно передается как null terminated wchar_t*, равно как и остальные простые типы.

 
A100 #:

Назвать указателем и при этом не сделать хотя бы равнозначным обращения (1) и (2)

это как минимум не логично

Не логично, но по всей видимости, это "защита от дурака" так как MQL используют не только программисты и проще автоматом приводить типы и разыменовывать указатели. При этом, даже когда требуется передать в функцию указатель - абсолютно без разницы будете ли вы использовать просто имя обьекта или с '&'/GetPointer(). 

Причина обращения: