Search
Write a publication
Pull to refresh

Comments 39

В свое время разбирался с реализацией методов под gcc для архитектур ARM и AVR. Главный вывод, который я вынес из понятого — нельзя ничего предполагать и, если Вам нужен вызов метода, то единственный надежный способ — шаблоны и явный вызов метода в нужном месте, все остальное — «от лукавого».
А по поводу «страшилок» как нельзя лучше подходит старая фраза «В уставе караульной службы каждая строчка написана кровью военнослужащих, которые пытались делать по своему»
Согласен со всем.
Не понравилось что в страшилке не было описано почему оно так, с чем и пытался разобраться тоже.
С уважением отношусь к Вашим исследованиям, но это только часть айсберга. У каждого компилятора реализация указателей объектов класса отличается. Поэтому нужно аккуратно стрелять из этого оружия. На хабре была отличная статья на эту тему, но к сожалению быстро найти не смог.
часто имеют размер больше 8 байт.

Вывод: 16
Размер указателя на метод больше 8 байт.

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

В статье тоже добавил
Добавил что все для X86-64
Имел в виду, что указатель на метод 16 байт в 64 битах, и 8 байт в 32 битах.
У меня нет технической возможности проверить что происходит в компиляторах Microsoft, поэтому не особо про них рассказал. Однако протестировав онлайн компиляторы, я заметил что MSVC умеет анализировать структуру классов и удалять поле значения корректирования, если оно не требуется.

Нет, MSVC поступает иначе. Я прошу прощения за самоцитирование, но я делал доклад, где было упомянуто сравнение в том числе генерации кода указателя на метод: www.youtube.com/watch?v=Ak0u8PX5tRU (примерно с 15 минут)
(про вышеупомянутые ARM и AVR там тоже есть).
Как бы там ни было, не следует делать никаких предположений о том, что там под капотом, и не выходить за пределы языка.
Зачем ты тогда делал целый доклад про то что под капотом, если не следует делать предположений никаких?
Или смотреть ассемблер — это не предположение (или не под капотом?), а простой примерчик — это предположение о том что под капотом?
Я точно делаю что-то не то?
Иногда приходится читать ассемблер, особенно если имеешь дело с экзотической платформой. Или, куда более редко, писать компилятор или его часть.
С эти сложно поспорить, но как это стыкуется с предыдущими высказываниями?
UFO landed and left these words here

Только если вам очень повезет, и указатель на функцию-член действительно будет размером sizeof(void*).


Основные случаи когда это может быть не так — особенности реализации компилятора, множественное наследование, указатель на виртуальную функцию, отладочная информация.

UFO landed and left these words here

Адрес чего? Выше вы привели код, из которого можно понять, что там происходит получение значения машинного адреса указателя на указатель на функцию-член класса.


В таком случае указатель на указатель будет действительно sizeof(void*), но это уже следующий уровень косвенности.

UFO landed and left these words here
Я как-то не спорю ни с чем, просто хотел сказать что ассемблер тут не особо нужен вообще впринципе. Есть же надежная функция memcpy)
Ну и си сам по себе хорошо с памятью все достает и кладет. Можно при желании неявно вызвать тот же memcpy без его прямого вызова
UFO landed and left these words here
UFO landed and left these words here
Я однажды гуглил список всех УБ под С++, но не осилил их найти.
Теперь каждый раз когда что-то делаю в С++, узнаю что есть еще УБ где-то почему-то.
УБ похожи на покемонов.
Это точно все?
Например, нельзя иметь бесконечную рекурсию в C++.
Про то что указатель на функцию преобразовывать в void* тоже не очень законно тут тоже не вижу.
Или это + дока по си должны все закрыть?
Я согласен с несогласием, но про отладочную информацию это для красного словца было сказано или реально что-то такое есть?

Доказательств привести не могу, но теоретически оптимизатор может знать реальный адрес функции после девиртуализации какого-то экземпляра класса или link-time optimization.

Адреса членов-функций и членов-данных объекта класса вычисляются (если правильно помню) как смещение от указателя на объект this.
Ещё не рассмотрен случай виртуального наследования. Думаю, размер указателя ещё подрастёт.
Что-то я пробовал. Не особо росло в случае clang и gcc.
Если сможешь что-то нашаманить и скинуть, то буду рад.
Если брать указатель на неизвестную структуру, то в gcc и clang будет 16.
gcc: rextester.com/CUCL60020
clang: rextester.com/ZCB93726
Если брать msvc, мало понимаю что там и почему происходит. Там размер 24, и что-то может и есть.
msvc: rextester.com/SNU4983
Может, если будет не лень, могу попробовать разобраться что происходит в MSVC, если кому надо…
Я что-то вообще не понял, что у тебя за примеры. Там указатель на необъявленный класс везде. Я видел очень давно статью на RSDN, кажется, возможно переводную, где все эти вопросы очень подробно разобраны.
Ну подумай. Что может быть более неопределенное, чем указатель на необъявленный класс? И в каком случае компилятор не может делать предположения относительно стуктуры класса совсем?
Указатель на необъявленный класс — это максимальный размер. Или ошибаюсь?
Если мне память не изменяет, в той статье было написано, что некоторые компиляторы делают рискованную оптимизацию для необъявленных классов.
Вот тут я нашёл кусок статьи, которая рассматривает вопрос подробнее, чем твоя stackoverflow.com/a/13875868/8452129
Видел эту статью из 2003 года. Пришлось разбираться самому, потому что из кода видно только то что sizeof указателя на метод больше обычного указателя.

Насколько я понимаю, gcc и clang всегда используют минимум 2 слова, msvc пытается варьировать 1-3 слова, в зависимости от класса. Реймонд Чен писало про это: Pointers to member functions are very strange animals

gcc и clang всегда размером с 2 указателя
msvc как понял: 1 указатель + 3 32битных инта (ну и компиль обрубает эти инты, если не нужны по какой-то причине)
Sign up to leave a comment.

Articles