Ошибки, баги, вопросы - страница 2198

 
fxsaber:

Без разницы


При вводе, как оказалось, зависит от того, какие цифры набираешь. Некоторые не позволяет набирать. А что-то - позволяет.

Странное поведение... Если набрать целую часть числа меньше 12ти знаков, то может пропустить общее количество больше 14ти.

Подождём что ответят разработчики.

 
Прошу помощи сделать простую вещь
class A
{
public:  
  int i;
  
  A* operator *( const A &Value ) const
  {
    A* Res = new A;
    
    Res.i = this.i * Value.i;
    
    return(Res);
  }
};

void OnStart()
{
  A a, b, c;
  
  a.i = 2;
  b.i = 3;
  c.i = 5;
  
  A* d = a * b * c;
  
  Print(d.i); // 30
  
  delete d;
}

В коде хорошо видно, что должна быть утечка памяти. И именно это и происходит. Однако, как написать правильно, чтобы можно было "перемножать" объекты? С оператором "*=" все понятно, как и ясно в случае структур. А с классами как реализовать этот простой функционал?


ЗЫ А этот код

class A
{
private:
  A Tmp;
  
public:
  int i;
  
  A* operator *( const A &Value )
  {
    this.Tmp.i = this.i * Value.i;
    
    return(&Tmp);
  }
};

void OnStart()
{
  A a, b, c;
  
  a.i = 2;
  b.i = 3;
  c.i = 5;
  
  A* d = a * b * c;
  
  Print(d.i); // 30
}

Крашит ME по F7 и убивает Терминал по F5. Почему же мне так везет?!

 
fxsaber:

ЗЫ А этот код

Крашит ME по F7 и убивает Терминал по F5. Почему же мне так везет?!

class A
{
private:
  A Tmp;
  
public:
  int i;
  
  A* operator *( const A &Value )
  {
    this.Tmp.i = this.i * Value.i;
    
    return(&Tmp);
  }
};

void OnStart()
{
  A a, b, c;
  
  a.i = 2;
  b.i = 3;
  c.i = 5;
  
  A* d = a * b * c;
  
  Print(d.i); // 30
}

Возможно бесконечная рекурсия и переполнение стека.

 
Sergey Dzyublik:

Возможно бесконечная рекурсия и переполнение стека.

Безусловно, проблема в выделенном, но причина, похоже, глубже.

И во время выполнения, очевидно, никакой рекурсии быть не должно. 

 
fxsaber:
Прошу помощи сделать простую вещь
class A
{
public:
  A() {}
  A(const A& other) 
  {
   this.i = other.i;
  }
  
  int i;
  
  A operator *( const A &Value ) const
  {
    A Res;
    
    Res.i = this.i * Value.i;
    
    return(Res);
  }
};

void OnStart()
{
  A a, b, c;
  
  a.i = 2;
  b.i = 3;
  c.i = 5;
  
  A d = a * b * c;
  
  Print(d.i); // 30
}
Оверхед конечно будет, но если удобство важнее...
 
Комбинатор:
Оверхед конечно будет, но если удобство важнее...

Спасибо! Получается, что return объекта и "=" при определении объекта идут через доп. конструктор.

Хотелось бы на самом деле наглядную таблицу где-то посмотреть, в каких случаях идут вызовы конструкторов (и каких), а в каких - операторов. Сейчас все на уровне интуиции, а она сбоит, конечно.

 
fxsaber:

Хотелось бы на самом деле наглядную таблицу где-то посмотреть, в каких случаях идут вызовы конструкторов (и каких), а в каких - операторов. Сейчас все на уровне интуиции, а она сбоит, конечно.

если вы что-то возвращаете по значению, оно будет присвоено через копи-конструктор (если тот же тип) если это определение или оператор если нет.

void OnStart()
{
  A a, b, c;
  
  a.i = 2;
  b.i = 3;
  c.i = 5;
  
  A d = a * b * c;
  // код аналогичен A d(a * b * c);
  // будет вызван копи-конструктор.

  A e;
  e = a * b * c;
  // будет вызван оператор =
  // но копи-конструктор все равно нужен для множественного умножения
  
  Print(d.i); // 30
}
 
Комбинатор:

если вы что-то возвращаете по значению, оно будет присвоено через копи-конструктор (если тот же тип) если это определение или оператор если нет.

Четко сформулировано, Спасибо!


ЗЫ Запринтовал Ваш код

class A
{
public:
  A() { Print(__FUNCSIG__); }
  A(const A& other) 
  {
   Print(__FUNCSIG__);
   this.i = other.i;
  }
  
  ~A()
  {
   Print(__FUNCSIG__);
  }
  
  int i;
  
  A operator *( const A &Value ) const
  {
    Print(__FUNCSIG__);

    A Tmp;
    
    Tmp.i = this.i * Value.i;
        
    return(Tmp);
  }
};

void OnStart()
{
  if (true)
  {
    A a, b, c;
    
    a.i = 2;
    b.i = 3;
    c.i = 5;
    
    A d = a * b * c;

    Print(d.i); // 30
  }
  
  Print("Kill!");  
}


Результат

void A::A() // a
void A::A() // b
void A::A() // c
A A::operator*(const A&) const
void A::A() // Tmp
void A::A(const A&) // return
void A::~A() // Tmp
A A::operator*(const A&) const
void A::A() // Tmp
void A::A(const A&) // return
void A::~A() // Tmp
void A::A(const A&) // d
30
void A::~A() // a
void A::~A() // b
void A::~A() // c
void A::~A() // d
void A::~A() // return
void A::~A() // return
Kill!

Выделенные строки вызывают вопросы. Почему временные объекты не грохнулись сразу, как были использованы? Т.е. до вывода тридцати. Такие объекты грохнут мою машину, т.к. предполагается работа с десятками миллионов тиков. Каждый объект будет отжирать гигабайты ОЗУ, и совсем не хочется иметь вот такие временные объекты вместо того, чтобы сразу их убивать.

 
fxsaber:

Выделенные строки вызывают вопросы. Почему временные объекты не грохнулись сразу, как были использованы? Т.е. до вывода тридцати.

обычно временные объекты удаляются не сразу, а в конце контекста. в С++ если не ошибаюсь это прямо в стандарте прописано.

хотите быстрого удаления - управляйте контекстом.

void OnStart()
{
  if (true)
  {
    A a, b, c;
    
    a.i = 2;
    b.i = 3;
    c.i = 5;
    
    A d;
    {
      d = a * b * c;
    }

    Print(d.i); // 30
  }
  
  Print("Kill!");  
}

Правда придется сделать оператор =

 
A100:

У меня на новом графике только при повторном запуске пример заработал (все кнопки), что само по себе непонятно. Зато теперь понятно это

С открытием торгов указанный эффект (только при повторном запуске) пропал

Внесли правки в документацию. Проблема кода была в том, что отправка графику приказа на получение событий мыши является только постановкой команды в очередь графика. И если эта очередь не обрабатывается (например в выходные), то график не может принимать указанные события. В описание ChartSetInteger добавлено примечание и поправленный пример:

Примечание

Функция является асинхронной – это означает, что функция не дожидается выполнения команды, успешно поставленной в очередь указанного графика, а сразу же возвращает управление. Изменение свойства произойдет только после обработки команды в очереди графика. Для немедленного выполнения команд в очереди графика нужно вызвать функцию ChartRedraw.

Если требуется немедленно изменить сразу несколько свойств графика, то необходимо соответствующие функции (ChartSetString, ChartSetDouble, ChartSetString) выполнить в одном блоке кода и затем вызвать один раз ChartRedraw.

Для проверки результата выполнения можно использовать функцию, запрашивающую указанное свойство графика (ChartGetInteger, ChartGetDouble, ChartSetString). При этом необходимо иметь в виду, что данные функции являются синхронными и дожидаются результата выполнения.

Пример:

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
void OnInit()
  {
//--- включение сообщений о перемещении мыши по окну чарта
   ChartSetInteger(0,CHART_EVENT_MOUSE_MOVE,1);
//--- принудительное обновление свойств графика гарантирует готовность к обработке событий
   ChartRedraw();

  }


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