Russian Qt Forum

Программирование => С/C++ => Тема начата: SASA от Январь 20, 2010, 16:56



Название: Вызов методов через не валидные указатели.
Отправлено: SASA от Январь 20, 2010, 16:56
Код:
class A
{
public:
int  getI() { return 100; }
};

 ...

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

Метод вызывается, возвращается 100. Нормально ли это? Или это компилятор студии с оптимизировал?
Понимаю, если бы метод был статик...


Название: Re: Вызов методов через не валидные указатели.
Отправлено: Rcus от Январь 20, 2010, 17:04
Ну так указатель пусть будет, главное его не разыменовывать (явно или неявно попыткой доступа к vtbl)


Название: Re: Вызов методов через не валидные указатели.
Отправлено: BlackTass от Январь 20, 2010, 17:56
у нулевого указателя можно вызывать нестатические методы. Проблемы будут только если понадобятся члены объекта или та же vtbl


Название: Re: Вызов методов через не валидные указатели.
Отправлено: Tonal от Январь 21, 2010, 09:16
Эффект от вызова метода через невалидный указатель неопределён и зависит от процессора, компилятора, опций компиляции, ОС, погоды на марсе.
Т. е. в каких-то случаях функция может и отработать. :)
Для распространённых компиляторов под винду и линнь невиртуальная функция не использующая данных экземпляра и не вызывающая других методов скорее всего отработает как ожидалось. :)


Название: Re: Вызов методов через не валидные указатели.
Отправлено: SASA от Январь 21, 2010, 13:11
Для распространённых компиляторов под винду и линнь невиртуальная функция не использующая данных экземпляра и не вызывающая других методов скорее всего отработает как ожидалось. :)

Очень ошибкоопасное свойство языка :-\.


Название: Re: Вызов методов через не валидные указатели.
Отправлено: developer от Январь 21, 2010, 17:44
Нда, ето точно


Название: Re: Вызов методов через не валидные указатели.
Отправлено: Tonal от Январь 22, 2010, 09:19
Очень ошибкоопасное свойство языка :-\.
Не языка а конкретной реализации в конкретных компиляторах.
Ни чем не хуже обычного обращения по невалидному указателю или выхода за границы массива. :)


Название: Re: Вызов методов через не валидные указатели.
Отправлено: Igors от Январь 23, 2010, 21:27
Не понял юмора - а почему это не должно работать и при чем здесь оптимизация?

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

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

Значит в действительности вызовется ф-ция getIt(a) - ф-ция член, значит подается this как доп. параметр. Ф-ция  this не использует - ну и нет crash. Вот если бы она была виртуальной - тогда бы получили (и то не всегда  :))


Название: Re: Вызов методов через не валидные указатели.
Отправлено: Tonal от Январь 25, 2010, 09:26
Раз в стандарте написано, что поведение не определено, значит может быть всё, что угодно.
Например компилятор для отладки вставит код проверяющий валидность результата operator->.
Или выкинет строку a->getI(); после A * a = 0;, зная, что нулевой указатель можно только сравнивать, но не разименовывать. :)


Название: Re: Вызов методов через не валидные указатели.
Отправлено: Авварон от Январь 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();


Название: Re: Вызов методов через не валидные указатели.
Отправлено: BlackTass от Январь 25, 2010, 14:32
Кстати, а this можно менять? Типа if (!this) this = new A();
нет, this константный


Название: Re: Вызов методов через не валидные указатели.
Отправлено: Igors от Январь 25, 2010, 18:41
Раз в стандарте написано, что поведение не определено, значит может быть всё, что угодно.
Это где там такое написано про ф-цию член?

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

Или выкинет строку a->getI(); после A * a = 0;, зная, что нулевой указатель можно только сравнивать, но не разименовывать. :)
С какого перепугу? Короче: "учи матчасть"  :)


Название: Re: Вызов методов через не валидные указатели.
Отправлено: Tonal от Январь 26, 2010, 08:57
Цитировать
Гарантируется, что нулевой указатель не равен указателю на любой объект (в широком смысле слова, любые данные) или функцию. Гарантируется, что любые два нулевых указателя равны между собой. Разыменовывание нулевого указателя является операцией с неопределённым поведением.

Иначе говоря, реализация предоставляет специальное значение — константу нулевого указателя, которую можно присвоить любому указателю и такой указатель при сравнении не будет равен любому «корректному» указателю. То есть, можно считать, что нулевой указатель не содержит корректный адрес в памяти.
Отсюда (http://ru.wikipedia.org/wiki/NULL_%28%D0%A1%D0%B8%29#.D0.A0.D0.B0.D0.B7.D1.8B.D0.BC.D0.B5.D0.BD.D0.BE.D0.B2.D1.8B.D0.B2.D0.B0.D0.BD.D0.B8.D0.B5_.D0.BD.D1.83.D0.BB.D0.B5.D0.B2.D1.8B.D1.85_.D1.83.D0.BA.D0.B0.D0.B7.D0.B0.D1.82.D0.B5.D0.BB.D0.B5.D0.B9).
Т.е. для нулевого указателя гарантируется только возможность сравнения. Любое другое его использование вызовет неопределённое поведение.

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

Какой код куда можно добавить или убрать - забота стандарта языка и компилятора и к твоим представлением о реальности отношения не имеет. :)
Недавняя уязвимость в ядре Linux (http://www.linux.org.ru/view-message.jsp?msgid=3880660&page=1) как раз из таких "нереальностей" :)