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

 
Ilya Malev:

Проверил:

По-моему вы что-то не то проверяете.

B*b1=a;

такая запись в MQL означает копирование объекта a - в объект расположенный по указателю b1.  Вообще конечно это не должно было компилироваться.

А чтобы не мешать в кучу объекты и указатели, лучше использовать для указателей префикс p

 
Ilya Malev:

Проверил:

Пожалуйста, не закладывайтесь на это ошибочное поведение.

Здесь 2 проблемы(?):

  1. B *b1=a  - явная ошибка, компилятор воспринимает эту конструкцию, как вызов оператора копирования A::A(const A &)

  2. В первом случае, оптимизатор определил что A::A(const A &) пустая, нет членов - нет доступа по "указателю" (по факту, никакого кода для вызова оператора копирования не осталось, всё было вырезано)
       виртуальная B::f() не перегружается, поэтому вместо виртуального вызова был простой, в B::f() нет адресации к членам, поэтому доступ по "указателю" тоже был вырезан

    Во втором случае, A::f() - попытка виртуального вызова, имеется доступ по "указателю", а объекта a1 нет, т.к. для A *a1=b тоже был вызов пустого конструктора копирования A::A(const A &)
 
Ilyas:

Пожалуйста, не закладывайтесь на это ошибочное поведение.

Здесь 2 проблемы(?):

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

 
Alexey Navoykov:

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

Да, будем исправлять.

Приоритет выставлен низкий, т.к. рабочий код получается только для пустых классов

 
Ilyas:

Пожалуйста, не закладывайтесь на это ошибочное поведение.

Здесь 2 проблемы(?):

  1. B *b1=a  - явная ошибка, компилятор воспринимает эту конструкцию, как вызов оператора копирования A::A(const A &)

  2. В первом случае, оптимизатор определил что A::A(const A &) пустая, нет членов - нет доступа по "указателю" (по факту, никакого кода для вызова оператора копирования не осталось, всё было вырезано)
       виртуальная B::f() не перегружается, поэтому вместо виртуального вызова был простой, в B::f() нет адресации к членам, поэтому доступ по "указателю" тоже был вырезан

    Во втором случае, A::f() - попытка виртуального вызова, имеется доступ по "указателю", а объекта a1 нет, т.к. для A *a1=b тоже был вызов пустого конструктора копирования A::A(const A &)

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

1) Почему компилятор воспринимает конструкцию B* b1=a как вызов оператора копирования А::А(const A&), (а не вызов B::B(const A&), ведь слева от оператора= находится именно класс B)

2) Почему компилятор не выдал предупреждения "конструктор копирования отсутствует"

3) Почему допускается "простой" вызов методов для несуществующих объектов (в то время как попытка непосредственно вызвать B::f() выдает ошибку компиляции "вызов не статического метода")

4) Ну и почему компилятор допускает вообще "простой" вызов виртуального метода? По-моему, виртуальность никак не должна зависеть от наличия или отсутствия данных в объекте

 
Ilya Malev:

1) Почему компилятор воспринимает конструкцию B* b1=a как вызов оператора копирования А::А(const A&), (а не вызов B::B(const A&), ведь слева от оператора= находится именно класс B)

Совершенно верно.  Это ещё одна ошибка MQL, что компилятор свободно разрешает такие вещи:  B b = a;   Это нарушение принципов инкапсуляции.  В С++ такое не компилируется естественно, требуется явное приведение.  И в старых билдах MQL тоже такое нельзя было делать.  

 
Ilya Malev:

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

1) Почему компилятор воспринимает конструкцию B* b1=a как вызов оператора копирования А::А(const A&), (а не вызов B::B(const A&), ведь слева от оператора= находится именно класс B)

2) Почему компилятор не выдал предупреждения "конструктор копирования отсутствует"

3) Почему допускается "простой" вызов методов для несуществующих объектов (в то время как попытка непосредственно вызвать A::f() выдает ошибку компиляции "вызов не статического метода")

1) я написал что это явная ошибка, которую мы будем править в любом случае

2) конструктор копирования генерируется компилятором, если его не объявил пользователь

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

 
Ilya Malev:

4) Ну и почему компилятор допускает вообще "простой" вызов виртуального метода? По-моему, виртуальность никак не должна зависеть от наличия или отсутствия данных в объекте

Вы путаете тёплое с мягким.

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

 
Ilyas:

2) конструктор копирования генерируется компилятором, если его не объявил пользователь

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

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

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