Russian Qt Forum
Ноябрь 23, 2024, 11:59 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Вызов методов через не валидные указатели.  (Прочитано 7965 раз)
SASA
Гость
« : Январь 20, 2010, 16:56 »

Код:
class A
{
public:
int  getI() { return 100; }
};

 ...

A * a = 0;
a->getI();

Метод вызывается, возвращается 100. Нормально ли это? Или это компилятор студии с оптимизировал?
Понимаю, если бы метод был статик...
Записан
Rcus
Гость
« Ответ #1 : Январь 20, 2010, 17:04 »

Ну так указатель пусть будет, главное его не разыменовывать (явно или неявно попыткой доступа к vtbl)
Записан
BlackTass
Гость
« Ответ #2 : Январь 20, 2010, 17:56 »

у нулевого указателя можно вызывать нестатические методы. Проблемы будут только если понадобятся члены объекта или та же vtbl
Записан
Tonal
Гость
« Ответ #3 : Январь 21, 2010, 09:16 »

Эффект от вызова метода через невалидный указатель неопределён и зависит от процессора, компилятора, опций компиляции, ОС, погоды на марсе.
Т. е. в каких-то случаях функция может и отработать. Улыбающийся
Для распространённых компиляторов под винду и линнь невиртуальная функция не использующая данных экземпляра и не вызывающая других методов скорее всего отработает как ожидалось. Улыбающийся
Записан
SASA
Гость
« Ответ #4 : Январь 21, 2010, 13:11 »

Для распространённых компиляторов под винду и линнь невиртуальная функция не использующая данных экземпляра и не вызывающая других методов скорее всего отработает как ожидалось. Улыбающийся

Очень ошибкоопасное свойство языка В замешательстве.
Записан
developer
Гость
« Ответ #5 : Январь 21, 2010, 17:44 »

Нда, ето точно
Записан
Tonal
Гость
« Ответ #6 : Январь 22, 2010, 09:19 »

Очень ошибкоопасное свойство языка В замешательстве.
Не языка а конкретной реализации в конкретных компиляторах.
Ни чем не хуже обычного обращения по невалидному указателю или выхода за границы массива. Улыбающийся
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #7 : Январь 23, 2010, 21:27 »

Не понял юмора - а почему это не должно работать и при чем здесь оптимизация?

Код:
class A
{
public:
int  getI() { return 100; }
};

A * a = 0;
a->getI();

Значит в действительности вызовется ф-ция getIt(a) - ф-ция член, значит подается this как доп. параметр. Ф-ция  this не использует - ну и нет crash. Вот если бы она была виртуальной - тогда бы получили (и то не всегда  Улыбающийся)
Записан
Tonal
Гость
« Ответ #8 : Январь 25, 2010, 09:26 »

Раз в стандарте написано, что поведение не определено, значит может быть всё, что угодно.
Например компилятор для отладки вставит код проверяющий валидность результата operator->.
Или выкинет строку a->getI(); после A * a = 0;, зная, что нулевой указатель можно только сравнивать, но не разименовывать. Улыбающийся
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #9 : Январь 25, 2010, 11:39 »

я согласен с Igors - нужно представлять, что из себя представляет это в сях...
а именно
Код:
 int getI(struct A * this) { return 100; }

//и вызов
struct A * a = 0;
getI(a);

в общем вся вина ложится на программиста за передачу невалидного указателя...
По аналогии можно придраться к тому что нет такой проверки при вызове статик-фцнкций от указателя (new QString())->number("123") вместо QString()::number("123")

Кстати, а this можно менять? Типа if (!this) this = new A();
Записан
BlackTass
Гость
« Ответ #10 : Январь 25, 2010, 14:32 »

Кстати, а this можно менять? Типа if (!this) this = new A();
нет, this константный
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #11 : Январь 25, 2010, 18:41 »

Раз в стандарте написано, что поведение не определено, значит может быть всё, что угодно.
Это где там такое написано про ф-цию член?

Например компилятор для отладки вставит код проверяющий валидность результата operator->.
Нереально добавить проверку на каждое обращение по указателю. И вызов ф-ции члена никакого отношения к этому не имеет: a->getIt() означает просто getIt(a). Да, "a" плохой, так что его на стек нельзя помещать?

Или выкинет строку a->getI(); после A * a = 0;, зная, что нулевой указатель можно только сравнивать, но не разименовывать. Улыбающийся
С какого перепугу? Короче: "учи матчасть"  Улыбающийся
Записан
Tonal
Гость
« Ответ #12 : Январь 26, 2010, 08:57 »

Цитировать
Гарантируется, что нулевой указатель не равен указателю на любой объект (в широком смысле слова, любые данные) или функцию. Гарантируется, что любые два нулевых указателя равны между собой. Разыменовывание нулевого указателя является операцией с неопределённым поведением.

Иначе говоря, реализация предоставляет специальное значение — константу нулевого указателя, которую можно присвоить любому указателю и такой указатель при сравнении не будет равен любому «корректному» указателю. То есть, можно считать, что нулевой указатель не содержит корректный адрес в памяти.
Отсюда.
Т.е. для нулевого указателя гарантируется только возможность сравнения. Любое другое его использование вызовет неопределённое поведение.

operator-> разыменовывает указатель для обращения к члену - в данном случае вызову функции.
Запись a->getI(); идентична (*a).getI();

Какой код куда можно добавить или убрать - забота стандарта языка и компилятора и к твоим представлением о реальности отношения не имеет. Улыбающийся
Недавняя уязвимость в ядре Linux как раз из таких "нереальностей" Улыбающийся
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.123 секунд. Запросов: 23.