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

 
Перестало работать приложение метатрейдер 4, при запуске работает где-то секунду, потом появляется окошко торговли в один клик в верхнем левом углу (Buy/Sell) и затем приложение закрывается.
Есть варианты как это можно исправить?
За помощь заранее благодарен.
 
Ilya Malev:

Потому что в мкл так себя всегда ведут операторы =, ==, !=, !, && и || когда слева указатель, а справа типа "объект".

Да при чём здесь указатель.  Я же вам вот здесь уже ответил. Оно и без указателя так работает здесь.
 
Alexey Navoykov:
Там слева стоит объект B, почему для него вызывается (или генерируется) конструктор A::A(A&) ?  Это противоречит принципам ООП

Полностью с Вами согласен и уже написал, что это ошибка, которая будет правиться.

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

 
Ilyas:

    Можно долго спорить, как правильно, производить или нет "разыменование" указателя, если доступа по нему не будет?

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

Потому что список виртуальных методов - это часть информации объекта, не менее важная, чем собственно данные, и доступ к виртуальным методам - это и есть доступ по указателю. Например если я в своем примере напишу

  A* aa=a;
  B* b1=a;   
  b1=aa;
  b1.f();

То получу снова B::f(), хотя здесь уже явное идет присвоение указателю В* объекта А*, который и "скопирован" был из А, и находился по ссылке А* . Это уже глубже ситуация, чем вызов "не того" конструктора копирования. Хотя даже если бы у объекта не было виртуальных методов, проверить валидность указателя при доступе по нему следовало бы все равно. 

 
Alexey Navoykov:
Там слева стоит объект B, почему для него вызывается (или генерируется) конструктор A::A(A&) ?  Это противоречит принципам ООП

А Вы уверены что там вообще что-то вызывается? Я проверил в x32:

class A {
public:
        A()           { Print(__FUNCSIG__); }
        A( const A& ) { Print(__FUNCSIG__); }
} a;
class B : public A {
public:
        B()           { Print(__FUNCSIG__); }
        B( const B& ) { Print(__FUNCSIG__); }
} *b = a;
void OnStart() {}

Результат: A::A()
и больше - ничего!

 
A100:

А Вы уверены что там вообще что-то вызывается? Я проверил в x32:

Результат: A::A()
и больше - ничего!

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

 
Ilya Malev:

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

Вообще это неоднозначный вопрос. Например в C# такая проверка всегда есть, а в C++ только по необходимости, что даёт преимущество в скорости.

Ведь если вызывается метод, в котором нет обращения к полям объекта, то действительно нет смысла проверять указатель.  В сущности такой метод равносилен статическому.

 
Alexey Navoykov:

Вообще это неоднозначный вопрос. Например в C# такая проверка всегда есть, а в C++ только по необходимости, что даёт преимущество в скорости.

Ведь если вызывается метод, в котором нет обращения к полям объекта, то действительно нет смысла проверять указатель.  В сущности такой метод равносилен статическому.

В объекте может не быть данных вообще, но при этом он может реализовать абсолютно разное и критически важное поведение, например обращаться к каким-либо внешним данным особым зависящим от типа образом, или вообще выполнять особое действие. Не знаю как обосновать такой подход как "равносильность метода статическому (читай 100% не виртуальному) при отсутствии данных"

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

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

К сожалению, я ввёл всех в заблуждение, для конструкций

B *b=a;
B b=a;

вызывается оператор копирования, а не конструктор копирования.
Во втором случае, после вызова конструктора B()

В любом случае, будем сначала анализировать, потом править.

 

О, оказывается в мкл имеется автогенерация конструктора копирования (я думал, что его вообще нет, т.к. нельзя Class obj(other_obj), только через =). Но почему он не генерится если:

class Q
{
public:
   Q(Q&)=default;  // нельзя
   Q(int) {}       // из-за него копирующий конструктор исчез
};