Название: Прелестно Отправлено: OKTA от Сентябрь 30, 2014, 17:19 Нашел прелестную вещь, о которой не знал :D
Как думаете, что вылетит в дебаг? ;D Код
Даже так работает. Ломает мое представление о мире. Код
Название: Re: Прелестно Отправлено: Bepec от Сентябрь 30, 2014, 17:28 Я пару раз так тестировал. Ничего особенного, просто не создавайте переменных и ничего не вылетит :)
PS жду аргументированных объяснений почему так. Ибо сам не знаю, но пользуюсь :D Название: Re: Прелестно Отправлено: OKTA от Сентябрь 30, 2014, 17:29 Да это из серии "вопросы на собеседовании по С++" ;D
Как вызвать не статическую функцию без создания экземпляра класса? P.S. Сам не знаю, Верес ;D Название: Re: Прелестно Отправлено: Bepec от Сентябрь 30, 2014, 17:37 Можешь ещё жутче поизгаляться. Можно написать полностью консольное приложение на пустом указателе. Главное я уже написал - не создавать переменных :)
PS лично у меня пустота на месте знаний - как собственно работает вызов функции класса. Нигде этот момент не акцентируется :) Название: Re: Прелестно Отправлено: Old от Сентябрь 30, 2014, 17:42 Нужно вспомнить, что из себя представляет метод класса и как ему передаётся this. Ничего удивительного нет. Попробуйте в методе test распечатывать значение this и все станет понятно. :)
Название: Re: Прелестно Отправлено: OKTA от Сентябрь 30, 2014, 17:45 так что запишешь в Foo *foo, то и распечатает) Ставишь 0 - дает 0 ??? Понятнее не стало ;D
Название: Re: Прелестно Отправлено: Old от Сентябрь 30, 2014, 17:49 так что запишешь в Foo *foo, то и распечатает) Ставишь 0 - дает 0 ??? Понятнее не стало ;D Метод класса это обычная функция, которой первым параметром передаётся адрес размещения объекта (this). Ваша функция ничего ужасного с объектом не делает, вот если вы по адресу писать начнете, тогда начнутся чудеса.Название: Re: Прелестно Отправлено: Bepec от Сентябрь 30, 2014, 17:57 Теперь пустота заполнилась :) Благодарю.
Правильно я говорил что программирование - на 90% обман :) to OKTA: собственно не создавая переменные в классе, мы его не трогаем получается. Так что обращения по невалидному нет. :) Название: Re: Прелестно Отправлено: _Bers от Сентябрь 30, 2014, 21:00 Метод класса это обычная функция, которой первым параметром передаётся адрес размещения объекта (this). Ваша функция ничего ужасного с объектом не делает, вот если вы по адресу писать начнете, тогда начнутся чудеса. Это не совсем так. По стандарту обращение к функциям-членам класса по невалидному указателю - это UB. А это значит, что программу может заглючить независимо от того, что делает функция-член. Например, если класс полиморфный, то из-за невалидного указателя получается, что скрытый указатель на таблицу виртуальных функций тоже невалиден. Поэтому, вызов виртуальной функции-члена по невалидному указателю скорее всего приведет процесс к крашу. Вообще, на плюсах есть четкое разделение на так называемые "сишные структуры", они же - POD-типы. И на "полноценные классы". Фундаментальное отличие между ними заключается в том, что теоретически компилятор имеет право засунуть в "полноценный" класс любую свою отсебятину. Сегодня - это скрытый указатель на таблицу виртуальных функций. Завтра запилят рефлексию, и компилятор добавит ещё что нибудь. В этих условиях безопасность вызова "казалось бы ничего страшного не делающей" функции-члена - под вопросом. В любом случае нельзя закладываться на работоспособность функции-члена, которая запускается через объект, который находится в некорректном состоянии. Название: Re: Прелестно Отправлено: Bepec от Сентябрь 30, 2014, 21:06 Можно сократить до одного предложения.
Использовать сейчас можно, но никто не даёт гарантий. Собственно как и любую возможность с++ :) Название: Re: Прелестно Отправлено: Old от Сентябрь 30, 2014, 21:08 Использовать сейчас можно, но никто не даёт гарантий. Не представляю где это можно использовать. :)Название: Re: Прелестно Отправлено: Bepec от Сентябрь 30, 2014, 21:22 Ну лично я использовал когда строил архитектуру. Можно наплодить десятки и сотни классов без инициализации и проверить собственно архитектурку. И нет нужды описывать всё.
Название: Re: Прелестно Отправлено: Old от Сентябрь 30, 2014, 21:28 Ну лично я использовал когда строил архитектуру. Можно наплодить десятки и сотни классов без инициализации и проверить собственно архитектурку. И нет нужды описывать всё. ::)Не обижайтесь, но вы написали просто набор слов. :) Что такое "десятки и сотни классов без инициализации" и как с помощью этого можно проверить "архитектурку"? Название: Re: Прелестно Отправлено: _Bers от Сентябрь 30, 2014, 21:39 Можно сократить до одного предложения. Использовать сейчас можно, но никто не даёт гарантий. Собственно как и любую возможность с++ :) Стандарт гарантирует вам корректность некоторых возможностей. И соответственно компиляторы, которые действуют по стандарту. Никто не дает никаких гарантий на возможности, которые либо вообще не были описаны в стандарте, либо явно там обозначены, как UB. Ситуация приведенная в сабже описана в стандарте, как UB. Название: Re: Прелестно Отправлено: navrocky от Сентябрь 30, 2014, 22:08 Использовать сейчас можно, но никто не даёт гарантий. Не представляю где это можно использовать. :)Код
Название: Re: Прелестно Отправлено: Bepec от Сентябрь 30, 2014, 22:22 Мдамс. Берётся в уме класс с множеством сложных полей. С него лепим заглушку из методов, возвращающих одно и то же. И вуаля у нас N-ное количество классов, на которых можно испытывать что угодно.
А если делать стандартно, то нужно написать такой же класс заглушку, инициализировать все его поля и создавать с помощью new. Название: Re: Прелестно Отправлено: _Bers от Сентябрь 30, 2014, 22:57 Использовать сейчас можно, но никто не даёт гарантий. Не представляю где это можно использовать. :)Код
Ну вообще это боян. Ну да ладно... 1. проверка гарантированно сломается, если использовать множественное наследование. 2. this не может быть нулевым, иначе это - UB. Компилятор закладывается на то, что программист не дибил, а значит он не сделает UB, а значит this никогда нулем не будет, а значит на нуль проверять не обязательно - и выпиливает эту проверку. Поэтому, код сломается сразу же, как только вы попытаетесь собрать в режиме оптимизации. 3. А вообще данный код - это классика говнокода. И мусолил эту тему все, кому не лень. Если кому нибудь захочется подробностей - загуглите статью на хабре. Название: Re: Прелестно Отправлено: _Bers от Сентябрь 30, 2014, 23:05 Мдамс. Берётся в уме класс с множеством сложных полей. С него лепим заглушку из методов, возвращающих одно и то же. И вуаля у нас N-ное количество классов, Которые не нужны. Сама по себе идея налепить множество классов сильно смахивает на "архитектуру ради архитектуры", ну или ооп головного мозга. А если делать стандартно, То пишется код, который иллюстрирует "как это должно работать". Грубо говоря, примеры использования вашего механизма пишутся ещё до того, как вы начнете создавать сам механизм. И только после того, как был выработан дизайн, пишется реализация. На этом кстати, базируется техника программирования TDD. Все что нужно программисту - заставить код отработать так, как это было задумано с точки зрения использования. И тогда окажется, что 100500 непонятных классов, которые непонятно как использовать - не нужны. Это конечно моё ИМХО. Название: Re: Прелестно Отправлено: Bepec от Сентябрь 30, 2014, 23:12 Вот именно что имхо :)
И немного лирики напоследок - в любых словах есть смысл. И если человек хочет - он его увидит :) Название: Re: Прелестно Отправлено: Old от Октябрь 01, 2014, 06:37 И немного лирики напоследок - в любых словах есть смысл. И если человек хочет - он его увидит :) Если бы он был, то вы уже давно набросали бы примерчик на c++ с демонстрацией того, как это удобно использовать, но пока только поток слов. :)Название: Re: Прелестно Отправлено: Old от Октябрь 01, 2014, 07:12 Код
И когда такой класс мне сможет пригодиться? :) Название: Re: Прелестно Отправлено: Johnik от Октябрь 01, 2014, 07:18 И как отработает этот класс в подобном случае:
Код
Название: Re: Прелестно Отправлено: gil9red от Октябрь 01, 2014, 07:45 И как отработает этот класс в подобном случае: Код
Падением программы? :) если, вообще, такое скомпилируется :) Название: Re: Прелестно Отправлено: OKTA от Октябрь 01, 2014, 09:16 Скомпилируется даже с нулевым указателем, но да, вылетит)
Название: Re: Прелестно Отправлено: gil9red от Октябрь 01, 2014, 09:19 Скомпилируется даже с нулевым указателем, но да, вылетит) Ну что ж поделать, компилятор, по умолчанию, уверен, что программист имеет прямые руки и они из правильного места она растут, поэтому и не ругается на такое приведение :) Название: Re: Прелестно Отправлено: OKTA от Октябрь 01, 2014, 09:19 И тихо смеется, видя, как программист отстреливает себе ногу ;D
Название: Re: Прелестно Отправлено: GreatSnake от Октябрь 01, 2014, 10:18 В свете выше сказанного растолкуйте корявость сего хака
Код
PS. Сей хак понадобился, чтобы обойти Qt-ишный баг, который позволяет отрабатывать QShortcut-ам при клавиатурном грабе. PPS. QWidget::event() - protected. Название: Re: Прелестно Отправлено: Old от Октябрь 01, 2014, 17:28 Так проще:
Код
Название: Re: Прелестно Отправлено: Bepec от Октябрь 01, 2014, 17:35 А пояснить зачем?
Название: Re: Прелестно Отправлено: Old от Октябрь 01, 2014, 17:43 Название: Re: Прелестно Отправлено: GreatSnake от Октябрь 01, 2014, 17:53 Так проще: Код
Конечно было проще, если бы не Код
Название: Re: Прелестно Отправлено: Old от Октябрь 01, 2014, 17:58 Конечно было проще, если бы не А в QObject он паблик, я туда заглянул.Код
Название: Re: Прелестно Отправлено: Bepec от Октябрь 01, 2014, 18:35 Old - знать и не говорить, это подло по отношению к другим :D То, что мои слова до вашего разума не добились - не повод ехидничать, хотяя... Ваше право.
Название: Re: Прелестно Отправлено: Old от Октябрь 01, 2014, 18:40 Old - знать и не говорить, это подло по отношению к другим :D У нас прямо форум подлецов... 90% знают и не говорят... :)Там три строчки кода, может вам стоит с этим разобраться? Название: Re: Прелестно Отправлено: Bepec от Октябрь 01, 2014, 19:12 Вырванных из контекста :) Мб и стоит, я не знаю. Я вас собственно и спрашиваю, желая узнать :)
Название: Re: Прелестно Отправлено: Авварон от Октябрь 01, 2014, 22:48 Метод класса это обычная функция, которой первым параметром передаётся адрес размещения объекта (this). Ваша функция ничего ужасного с объектом не делает, вот если вы по адресу писать начнете, тогда начнутся чудеса. Цитировать thiscall © ВикаИспользуется в компиляторах C++. Обеспечивает передачу аргументов при вызовах методов класса в объектно ориентированной среде. Аргументы передаются через стек, справа налево. Очистку стека производит вызываемая функция, то есть тот же самый stdcall. Указатель (this) на объект, для которого вызывается метод, записывается в регистр ECX. Название: Re: Прелестно Отправлено: Old от Октябрь 01, 2014, 22:51 А там не сказано что делать, если у процессора нет регистра ecx? :)
Название: Re: Прелестно Отправлено: Авварон от Октябрь 01, 2014, 22:54 Я думаю, регистры есть примерно во всех архитектурах. Поинт в том, что врядли this передаётся через стэк - это медленно.
Название: Re: Прелестно Отправлено: Авварон от Октябрь 01, 2014, 22:56 ЗЫ: вам, кстати, должно быть известно, что архитектур, кроме х86, не существует http://msdn.microsoft.com/en-us/library/ek8tkfbw(v=vs.71).aspx :)
Название: Re: Прелестно Отправлено: Old от Октябрь 02, 2014, 06:28 Я думаю, регистры есть примерно во всех архитектурах. Поинт в том, что врядли this передаётся через стэк - это медленно. Да не принципиально как он передаётся (это все отдается на откуп abi конкретной платформы), главное что он передаётся в функцию в качестве параметра.Я простым языком хотел объяснить, что метод это обычная функция с дополнительным параметром. :) P.S. Я очень часто пишу на форум с телефона, поэтому подробно расписывать у меня терпения не хватает. :) Название: Re: Прелестно Отправлено: gil9red от Октябрь 02, 2014, 06:51 Я думаю, регистры есть примерно во всех архитектурах. Поинт в том, что врядли this передаётся через стэк - это медленно. Да не принципиально как он передаётся (это все отдается на откуп abi конкретной платформы), главное что он передаётся в функцию в качестве параметра.Я простым языком хотел объяснить, что метод это обычная функция с дополнительным параметром. :) P.S. Я очень часто пишу на форум с телефона, поэтому подробно расписывать у меня терпения не хватает. :) Как в python, только не так открыто для программиста :) Название: Re: Прелестно Отправлено: GreatSnake от Октябрь 02, 2014, 09:43 Ну так что, кто-нибудь что-либо скажет насчёт этого (http://www.prog.org.ru/index.php?topic=27677.msg201421#msg201421)?
Название: Re: Прелестно Отправлено: _Bers от Октябрь 02, 2014, 10:00 Я простым языком хотел объяснить, что метод это обычная функция с дополнительным параметром. :) Вы пишите об этом так, словно компилятор, встретив вызов функции-члена, генерирует код вызова обычной функции, передав в качестве первого аргумента - адрес объекта. Вы пишите так, словно можно закладываться на работоспособность следующего кода: http://rextester.com/RSDW27510 Код: #include <iostream> Представленный выше код дает представление о том, чем на самом деле является функция-член. А так же иллюстрирует принципиальную схему действий компилятора. Однако, несмотря на то, что представленный код работает в большинстве случаев - он является UB. И компилятор, который мне пришлось обмануть, что бы выполнить каст, не зря запрещает такой каст. По факту, по месту вызова функции-члена, компилятор должен сгенерировать вызов. Но каким именно он будет - зависит от его способности к оптимизации. Если компилятор знает про все конкретные вызовы функции-члена, то он может изменить и код вызовов функции-члена, и саму функцию-член как угодно. Единственное: он гарантирует, что при этом не изменится так называемое "наблюдаемое поведение". Поведение программы по прежнему будет соответствовать исходному коду. Но при этом компилятор закладывается на то, что программист не делает UB. А значит он не делает преобразований типов, которые запрещено делать. А значит можно изменить вызов так, что бы параметры прошли через регистры, или ещё каким то особым образом. А это означает, что "хакнутый" указатель на свободную функцию теоретически может отказать в любой момент. Компилятор запрещает данные касты, специально, что бы пользователи не могли закладываться на конкретную стратегию вызова. Это поведение описывается в стандарте как unspecified behaviour. Что означает: компилятор сгенерирует "правильный" код вызова функции-члена, но каким именно он будет - нельзя знать наверняка. И это нужно компиляторам для того, что бы максимально развязать им руки в плане всевозможных оптимизаций Название: Re: Прелестно Отправлено: _Bers от Октябрь 02, 2014, 10:03 Ну так что, кто-нибудь что-либо скажет насчёт этого (http://www.prog.org.ru/index.php?topic=27677.msg201421#msg201421)? Это UB Считайте что вам просто повезло, что при одиночном наследовании указатель на vtable всегда лежит в начале объекта и совпали индексы функций в нем. (примечание: вроде бы не гарантируется что это всегда будет именно так) Код, который наглядно иллюстрирует возможные проблемы: http://ideone.com/KPiDmR http://ideone.com/z0bAgC Название: Re: Прелестно Отправлено: Old от Октябрь 02, 2014, 10:05 Вы пишите об этом так, словно компилятор, встретив вызов функции-члена, генерирует код вызова обычной функции, передав в качестве первого аргумента - адрес объекта. Вовсе нет. :)Посмотрите на начало обсуждения, я постарался просто объяснить, почему код ТС не падает. Я не собирался вдаваться в подробные объяснения всех механизмов для всех возможных ABI. Это я оставил для самостоятельного изучения ТС. Название: Re: Прелестно Отправлено: OKTA от Октябрь 02, 2014, 12:54 Что-то я читал, читал твой пример, _Bers и так и не понял, что ты хотел им показать. Я так понял, что как раз фишку, что передается адрес объекта? ???
Название: Re: Прелестно Отправлено: OKTA от Октябрь 02, 2014, 21:31 up или че там говорят обычно? ;D
Название: Re: Прелестно Отправлено: Igors от Октябрь 05, 2014, 11:04 Ну так что, кто-нибудь что-либо скажет насчёт этого (http://www.prog.org.ru/index.php?topic=27677.msg201421#msg201421)? Единственное что могу сказать - сам делал практически так же :)Др пример Код: ARGB CalcColor( void ); Это не работает если тело CalcColor в С (не cpp) файле. Когда ф-ция вызывается из cpp, она рассчитывает на Код и подает "с" как аргумент. Правда варнинг есть, что-то типа "inconsistent linkage" (точно не помню) Непонятно удивление на 4 страницах :) Самые начальные познания в ассемблере снимают все вопросы Название: Re: Прелестно Отправлено: Bepec от Октябрь 05, 2014, 12:17 Тупо не преподавали этот материал, а на практике он не пригождается.
Название: Re: Прелестно Отправлено: Igors от Октябрь 05, 2014, 13:36 Тупо не преподавали этот материал, а на практике он не пригождается. Если человек не представляет во что это выливается в командах - ему на уши можно повесить любую лапшу (что нередко и делают на хабре, да и местные знатоки..)Что-то я читал, читал твой пример, _Bers и так и не понял, что ты хотел им показать. Я так понял, что как раз фишку, что передается адрес объекта? ??? Упрощенный пример Код Полагать что действительно на стек будет подаваться num, затем p1 и p2 - ну так думают тыкающие мальчики :) Реально может быть что угодно, напр num в регистре ecx p0 и p1 в регистрах FP2 и FP3 Никакой подачи не стек не происходит, ф-ция просто скомпилирована так что рассчитывает на аргументы в этих регистрах. Теперь Вы берете адрес ф-ции и вызываете ее "как положено" - но она об этом ничего не знает Название: Re: Прелестно Отправлено: Old от Октябрь 05, 2014, 14:23 Для того, что бы таких заморочек не было, давным давно были приняты соглашения о вызовах с соответствующими директивами и все это расписывается в abi конкретной платформы.
Название: Re: Прелестно Отправлено: Bepec от Октябрь 05, 2014, 15:07 Замер производительности команд/функций вполне заменяет знание ассемблера, увы.
|