Нашли или выдавили из себя код, который нельзя назвать нормальным,
на который без улыбки не взглянешь?
Не торопитесь его удалять или рефакторить, — запостите его на
говнокод.ру, посмеёмся вместе!
Пытался продемонстрировать статический полиморфизм TarasB и получилась такая какашка. Кто действительно крут и может сабдж продемонстрировать? Я где-то видел пример, но не помню где...
Ещё продемонстрировал статический полиморфизм через стратегии:
struct Strategy1
{
static void do(){printf("Lol1");}
};
struct Strategy2
{
static void do(){printf("Lol2");}
};
template<class Strategy>
class MegaClass
{public:
void do()
{
printf("Mega");
Strategy::do();//Класс Strategy можно было и создать для хранения состояния.
printf("/n\");
}
};
//...
Дальше в разных частях кода создаем:
MegaClass<Strategy1> o;
o.do();
//...
MegaClass<Strategy2> o;
o.do();
"Один" класс ведёт себя по разному. Понятно, что это не совсем полиморфизм. Но очень часто именно в таком контексте используют динамический полиморфизм, хотя такого статического здесь достаточно выше крыши.
Плюсы этого подхода :
1)Создаётся объект в стеке, значит быстро, а не в куче. Хотя можно и не в стеке.
2)Используется шаблон, значит компиль будет инлайнить.
Минус:
1)Если понадобится резкой перейти от статического полиморфизма к динамическому - придётся переписывать на виртуальные функции или на истинный статический полиморфизм.
>>1)Создаётся объект в стеке, значит быстро, а не в куче. Хотя можно и не в стеке.
done
>>2)Используется шаблон, значит компиль будет инлайнить.
А в результате - приведение типов через reinterpret_cast, нельзя создать массив полиморфных объектов без е..ли и вообще грязь в коде. Смысл?
смысл в инлайне
вызовы функций через указатели не инлайнятся. более того, если на функцию создатся хотя бы один указатель, она вообще не может инлайнится
-у с++ особый нрав. это как необузданный мустанг из прерий
-точно, а я то думаю, кого он мне напоминает
-но зато он самый быстрый, сильный и гибкий
но чуть ты оплашаешь - обязательно упадешь на большой скорости вниз под копыта
приготовься и запасись терпением. пройдет много времени, прежде чем он тебя зауважает и ты почувствуешь себя его хозяином
для виртуальных функций:
первый указатель: указатель на объект (он есть, даже если объект создан в стеке)
второй указатель на VTBL (таблицу виртуальных методов)
третий указатель на виртуальный метод
для не виртуальных методов:
тупо вызывается метод, с зафиксированным константным адресом в опкоде комманды call, что намного быстрее для вызова, даже чем через обычный 1 указатель.
Например, хранить в объекте указатели на методы. Так делают ООП на Си и в языках, где можно изменить метод для отдельного объекта. Больше расход памяти (пропорциональный количеству объектов и количеству методов), но на один уровень косвенности меньше при вызове. Если в некоторой иерархии всего один виртуальный метод и не используется rtti, то оверхеда нет и это бесспорная оптимизация.
Можно придумать и другие способы. Например, в виртуальной таблице хранить не указатели, а сами методы (в элементах фиксированного размера). Небольшие поместятся все, для больших — команда перехода (или начало и команда перехода). Увеличение расхода памяти не зависит от числа объектов, и на один уровень косвенности для малых методов меньше (для которых это имеет смысл).
Можно избавиться от указателя на таблицу, если объекты разного типа распределять в разных областях памяти. Тогда тип однозначно определяется указателем (старшими битами). В принципе, это реально организовать даже на современных 64-битных процессорах. С стековыми объектами придётся повозиться (по сути на стеке это будут только прозрачные умные указатели), этот способ больше подходит для Java или C#.
>Например, хранить в объекте указатели на методы. Так делают ООП на Си
Это понятно. Только вот на си этот метод не к месту. Если пишешь для небольших контроллеров - каждый байт на счету. А тут растраты на пустом месте...
Между прочем сишники упорно, даже для контроллеров, продолжают эмулировать ООП. То, что оно удобно заставляет их использовать это периодически и ничего в этом плохого нет. Есть разные задачи для контроллеров, где это уместно. Для контроллеров даже на С++ пишут.
1% в редких программах на редком вызове? Это даже не стоит обсуждать. Экономия на спичках.
>Если в некоторой иерархии всего один виртуальный метод и не используется rtti, то оверхеда нет и это бесспорная оптимизация.
Ох какая бесспорная... Виртуальных методов обычно или 0 или >=2. Случая с одним просто нет. Обычно, если появляется хоть один метод, то сразу появляется и виртуальный деструктор. А rtti вообще по стандарту языка должен быть, если есть виртуальные методы. А rtti это ещё один указатель\виртуальный метод.
Нет, в редких программах, вовсю использующих быстрые виртуальные объекты-функторы, выгода может быть намного больше, десятки процентов. Да, при этом эти объекты не должны передаваться во владение. Создали объект, передали по ссылке/указателю в функцию, где он используется миллион раз, после возврата сами же и уничтожили.
RTTI должен быть, если его используют. А если нет для какой-то иерархии dynamic_cast или typeid, то и не нужен.
Эту оптимизацию и вручную сделать можно, указателем на функцию, но если компилятор сам заметит, приятно.
>RTTI должен быть, если его используют.
Если хоть в одном классе данной иерархии он используется, то его придется использовать везде, иначе кастить не получится этот объект.
Если хотя бы в одном классе данной иерархии 2 виртуальные функции, то придется заводить указатель на таблицу виртуальных функций во всей иерархии, иначе кастить также не получится.
А с учетом современных тенденций: один класс предок на всю иерархию программы, например как QObject в QT или System.Object в C#, то эта оптимизация совсем работать не будет.
Сила текущей организации vtbl в объекте в том, что это наиболее эффективное решение, но при этом универсальное, поэтому компилятор очень прост не обременен анализом мелких редких частных случаев, не дающим особого выигрыша в реальных условиях.
А между тем компилятор не сможет оценить всю иерархию классов, тк часть классов используется в одной единице трансляций, а часть в другой. А это уже медленный глобальный анализ всего кода всех obj файлов. Линкер повесится, не смотря на то, что это не его работа.
Вопрос межмодульного анализа и оптимизации до сих пор почти не решен ни в одном языке., тк это пока не по зубам современным компьютерам из-за ограничения производительности.
Если вам что-то не нравится, то напишите свой компилятор или вы знаете, где найти assembler и ansi C для экономии на редко встречающихся спичках в своих программах.
Вы часто используете dynamic_cast и typeid? Я — нет, а когда использую, это ограничивается небольшой определённой иерархией классов. C++ позволяет не производить классы от одного суперкласса, и большинство пользовательских классов таки не наследуются от него, даже если используются библиотеки с суперклассами (у каждой своим).
Некоторые способы оптимизации (например, dynamic_cast за O(1)) требуют знание о всей иерархии классов. Сейчас компилятор и редактор связей намного умнее, чем были 30 лет назад.
>Вы часто используете dynamic_cast и typeid?
Я - нет, но QT все время. Выигрыш от метода теряется полностью на всех классах QT приложения.
>Сейчас компилятор и редактор связей намного умнее
Вот только не надо. Вижу я этот "ум и гениальность" межмодульной оптимизации каждый день, особенно в GCC или MSVC... И это при часовых компиляциях. А что будет, если добавить ещё больше "ума" межмодульному оптимизатору?
Не подходит С++ для нормальной межмодульной оптимизации., особенно с его препроцессором и включаемыми файлами. 2 этих фактора нарушают легкость межмодульной оптимизации. Компилятору приходится генерировать код, не нарушающий ODR (я про ODR машинного уровня, а не уровня кода), что не так просто, если сделать его "сильно умным" и при этом ошибиться хоть где-нибудь.
С QT не сталкивался, но используя Qt, не обязательно все свои классы наследовать от QObject (и в Qt не все классы входят в эту иерархию). Да вы можете использовать классы вообще без виртуальных методов и какой-либо vtable.
Если убрать указатель на VTBL, используя эти нестандартные оптиизации, то пропадет совместимость экспортируемых объектов COM, а сейчас оный и его аналоги даже в линуксе используются.
Какой ещё ком-шном? Ничего такого в стандарте языка нет. А C++ всегда был ориентирован на монолитные блобы, и многие оптимизации рассчитаны на доступность всего кода. Для внешних интерфейсов можно использовать общепринятый ABI, а что там внутри — это наше дело.
>Ничего такого в стандарте языка нет.
Зато есть стандарт де факто и его также желательно поддерживать. Иначе под туже винду нельзя будет легко писать, ибо там COM в моде, особенно с выходом "ЭпикВин8".
Вы это скажите тем, кто по прежнему пишут. Да и не нужно забывать о C++\CLI, на коем пишут и под .NET Framework под винду и могут юзать COM. А под винду 8ку появится и C++\CX, на который делает ставку майкрософт в ущерб даже шарпам и прочим управляемым языкам.
Вообщем, терять совместимость из-за копеечных сомнительных оптимизаций при усложнении компиля - не вариант.
Ну вот, под винду свой особый диалект C++, несовместимый со стандартом. Всё равно ведь для того, чтобы сделать COM, нужны дополнительные действия, за пределами языка? И ничто не мешает это использовать для внутренних классов, невидимых снаружи. На совместимость это не повлияет. Может быть нужны будут специальные подсказки компилятору (прагмы), а может и сам догадается.
Все уже продумано и во всю используется. Почитайте хотя бы про COM, ABI, что б хоть представлять что это такое. Я уже говорил про стандарт де факто, который вы так хотите нарушить.
Я не говорю, что это хорошо, но это реальный способ, он использовался ещё тогда, когда ни о каких внутрипроцессорных кешах никто и не слышал. И продолжает использоваться и поддерживаться сейчас.
Ещё один недостаток — увеличивается время создания объекта (нужно проинициализировать все указатели на методы).
Это не я предлагаю, это так есть. Полагаю, что GTK и сейчас так устроено. Qt, кстати, со своими динамическими сигналами, тоже. Вообще, любая гуишная ОО модель содержит в объектах сказатели (или списки указателей) на обработчики. Практически каждый динамический ОО язык.
>любая гуишная ОО модель содержит в объектах сказатели (или списки указателей) на обработчики
Что за капитанство? Qtшные классы во внутреннем устройстве не имеют никакого то отклонения от стандарта де факто, использующего VTBL. Все компилится и обычным С++ компилем + кодогенератором препроцессорного типа. Ничего менять в устройстве класса из-за QT не нужно и никто этого не делает.
>это так есть.
Я ещё раз спрашиваю примеры?
>Полагаю
Нечего полагать. Я жду фактов или объяснения большей оптимальности или необходимости такого метода.
С GTK я работал достаточно давно, не помню, как там устанавливаются обработчики. Но любая современная объектная гуишная система имеет либо члены в объектах, куда сохраняются указатели, либо глобальный реестр (как в FOX Toolkit) — тоже способ реализации виртуальных методов, громоздкий и медленный.
Компилируется Qt не обычным компилятором C++, используются свои расширения языка, которые уже компилируются в C++. Напомню, что первый компилятор C++ компилировал в C.
>Но любая современная объектная гуишная система имеет либо члены в объектах, куда сохраняются указатели — тоже способ реализации виртуальных методов, громоздкий и медленный.
Это проблемы этой библиотеки. К реализации виртуальных методов в языке - GUI-библиотеки не имеют никакого отношения. И если вы и говорите, что эта реализация медленная, так зачем предлагать её в качестве оптимизации для компилятора С++?
>Компилируется Qt не обычным компилятором C++
Я уже сказал, что QT проги компилируется обычным компилятором С++, предварительно прогнав код через кодогенератор препроцессорного типа. Теперь понятно, почему аргументы не доходят до вас и вы продолжаете без конца повторять одно и тоже. Если вы не внимательно читаете, то я не могу ничем вам помочь. Я не могу читать за вас. Видимо, это сигнал мне закончить разговор с вами.
>Например, в виртуальной таблице хранить не указатели, а сами методы (в элементах фиксированного размера).
Это вообще не слабое разбухание кода для очень разветвленных иерархий. Придется на каждый отдельный класс хранить свою таблицу кода абсолютно одинаковых функций.
Не такое уж сильное, ведь в таблицу поместятся только небольшие функции. Будет не 8 байт на метод, а пусть 128, таблица класса с полусотней методов займёт не 400 байт, а на 6 килобайт больше — тьфу. Большие функции всё равно займут килобайты и десятки килобайт. Так что в процентном отношении код вырастет не сильно. А если ещё учесть мегабайты данных…
>таблица класса
А таких классов может быть много, не забывайте обо всех потомках и предках этого класса в иерархии с перекрывающими методами. А это много классов с абсолютно одинаковыми копиями методов. Особенно эпичный фейл ждет, если вспомнить современные тенденции к кодогенерации и шаблонам, то это уже будет нереально много классов с абсолютно одинаковыми копиями методов.
И вообще это не кешфрендли.
Хватит предлагать методы, что не подходят современным реалиям, а использовались разве что отцами.
А может быть и не много (по сравнению с количеством объектов). Например, в геометрической модели ограниченное число классов (вершины разного типа, рёбра, грани и полигоны разного типа), размер каждого объекта — от 32 до сотни байт, а самих объектов — миллионы (т.е. данные занимают места на несколько порядков больше кода). Виртуальные методы могут быть достаточно просты (количество вершин элемента, вершина по номеру), чтобы лишний уровень косвенности при вызове был но заметен. Если компилятор, пошуршав несколько часов, выдаст бинарник, который просчитывает задачу на 20% быстрее, — честь ему и хвала.
Кстати, о кеше. Если разделять кеш для данных и кода, то код пары десятков классов осядет в кеше, а вот vtable с указателями будет постоянно выталкиваться из него обрабатываемыми данными. Но это частности.
А может быть, да кабы, да во рту выросли грибы. Из-за кодогенерации и шаблононов С++ классов очень много. Не хочу иметь дубликат всех функций map для каждой комбинации его шаблонных параметров. Проект и так долго компилируется, а тут ещё и кучу дубликатов. Полумеры не рулят. Ещё этот метод заставляет вставлять лишние джампы в конце каждой большой функции из таблицы, что также не кешфрендли.
>а вот vtable с указателями будет постоянно выталкиваться из него обрабатываемыми данными
Да ладно? Обычно виртуальные функции используются часто, так что не будет выталкиваться.
>от 32 до сотни байт, а самих объектов — миллионы
Эта задача - ещё один сферический кот в вакууме, которых вы так любите приводить в качестве примеров.
>Если компилятор, пошуршав несколько часов, выдаст бинарник, который просчитывает задачу на 20% быстрее, — честь ему и хвала.
Чтобы получить приличный прирост к производительности - нужно оптимизировать алгоритм, а не экономить на спичках (на инструкциях). Компилятор за вас говноалгоритм не перепишет. Если же вам нужна экономия на спичках, я уже сказал, где её найти (Си\асм).
Джамп (только не в конце, а в начале-середине) больших функций как раз соответствует текущей модели vtable.
Ну что поделать, вот с такими сферическими конями приходится иметь дело. Это комы да дотнеты для меня экзотика.
Писать такое на Си или, тем более, ассемблере — безумие, код засорится и помешает высокоуровневой оптимизации. А вот если компилятор бесплатно и прозрачно её проведёт, то можно на такие детали не обращать внимания и заняться алгоритмами.
>Джамп в начале больших функций как раз соответствует текущей модели vtable.
Поэтому и не было смысла вводить эту оптимизацию. Если вспомнить все вышеперечисленные её недостатки.
>std::map не имеет виртуальных методов.
Ага, а все пользуются только им и шаблонных классов с виртуальными методами не используют. Ну-ну...
>можно на такие детали не обращать внимания и заняться алгоритмами.
Вот и займитесь этим наконец. Не нужно валить все беды с больной головы на здоровую. Нечего обвинять компилятор во всех грехах. Если что-то тормозит - программист написал плохой код и использовал плохой алгоритм. Из-за вашей экономии на спичках прироста не будет, а как мы выяснили уже - одни беды.
>Можно избавиться от указателя на таблицу, если объекты разного типа распределять в разных областях памяти. Тогда тип однозначно определяется указателем (старшими битами).
Хаки какие то. Это особенно поможет, когда предков у класса 100500. Заведем бесконечное адресное пространство и будем перед каждым вызовом виртуальных функций делать побитовые операции (мега оптимизация) и не понятно как потом определять, какой виртуальный метод вызвать. При этом со стеком в С++ этот метод ждет фейл и тормоза, тк нужно дергать медленный менеджер памяти, а не быстрый стек. И да, придется сделать "особый магический" менеджер памяти для размещения в разных адресах адресного пространства, предварительно переписав ОС, чтобы та позволяла 100% разместить все объекты по конкретным адресам и быстро. А когда адресное пространство с данным битом заполнится до отказу объектами данного типа, программу ждет bad_alloc при почти пустой памяти, а программиста батхерт. Нечего было создавать так много объектов данного типа! Особенно забатхертятся программисты под DOS. Эпичный пафос и пафосный эпос. (:
Выделим старшие 20 бит на код класса — миллиона классов хватит? Битовые операции могут быть быстрее обращения к памяти (особенно, если будет поддержка процессором). Виртуальный метод определяем точно так же, по индексу в таблице, адрес которой дадут старшие биты адреса объекта. Менеджер памяти будет почти такой же быстрый, как стек, ведь он работает с объектами одинакового размера. ОС переписывать не нужно, если только она не написана на C++, всё необходимое уже поддерживается. Доступное для класса адресное пространство на порядки превышает доступные в обозримом будущем объёмы физической памяти (и только на инициализацию понадобиться много времени).
>DOS?
А по вашему GCC не должен компилировать под DOS или под микроконтроллеры? А то что этот метод не совместим с текущими отлаженными бекендами вас не смущает? А то что этот метод не совместим с текущим стандартом С++, например с кастомными аллокаторами или перегрузкой операторов С++ вас тоже не смущает? А то что это метод сильно замедляет работу со стековыми объектами, взамен мелкой экономии на спичках - вас это также не смущает? А то, что винда не позволяет выделять с гарантией по конкретным адресам объекты и может выделить при этом без смущения по другим? С системой куч винды это не совместимо. И тем более винда не позволяет выделять память по заданным регионам? Вас не смущает, что оси придется переписывать. А не смущает ли вас, что в разных версиях осей какие то диапазоны заняты под системные объекты полностью и не доступны для выделения, зато они доступны в других? Придется под каждую ось компилировать отдельно?
Где вы взяли 64-битный DOS и зачем? И почему вы против архитектурно-специфичных оптимизаций?
К перегрузке операторов это не имеет никакого отношения. Работу с автоматическими переменными практически не замедлит (в той же области видимости всё равно виртуальность исчезнет). Как там в виде не знаю, это её проблема, ну значит будут под неё программы медленнее. А так ведь можно отмапить максимально возможное адресное пространство и использовать по своему усмотрению. Не думал, что в современных ОС прикладные программы работают с физической памятью и по абсолютным адресам. Ну да это проблемы этих ОС (кстати, обычно программы таки компилируются отдельно под разные ОС и под разное железо, иногда даже разными компиляторами).
Мне интересно, где вы его взяли? А С++ компилятор должен компилировать и под DOS и под МК, но я вам уже это говорил. Но видимо, для вас нужно много раз повторить, прежде чем дойдет.
>И почему вы против архитектурно-специфичных оптимизаций?
Вот когда поработаете над кроссплатформенными проектами, тогда и поговорим. См ниже.
>К перегрузке операторов это не имеет никакого отношения.
Да ладно? А как же вы через стандартный malloc затребуете память по определенному региону? Если это архитектуро-специфичная "оптимизация", то как же вы будете перегружать оператор new? Под одну платформу с использованием регионов, а под другую без? Решили добавить ещё одну причину писать программисту дубликаты кода под разные платформы? Обойдемся.
>Работу с автоматическими переменными практически не замедлит.
Замедлит и ещё как. В стеке память выделяется за одну инструкцию проца, а вы предлагаете вызывать тормозную кучу с очень большим не детерминированным временем выделения и освобождения памяти. А между тем автоматических объектов в С++ большинство в среднестатистической программе. "Хорошая" оптимизация у вас получилась...
То, что винда не поддерживают распределение по регионам - это точно. Аналогично и в других осях. Это гениальная идея - переписать винду под С++ с вашей мегооптимизацией. Атцы одобрят.
>Ну да это проблемы этих ОС
По моему эта ваша личная проблема и пользователей вашего "компилятора".
Это вы зачем-то приплели DOS. В разговор о деталях реализации для 64-битных машин с виртуальной страничной памятью.
Это (а также другие ваши реплики) показывает, что вы совершенно не слушаете собеседника, а значит продолжать эту дискуссию бессмысленно. А с учётом вашего тона — и нежелательно.
🙂 void * - и только на с. Рекомендую тсс, зверек неухоженный но классы дергает только так даже в режиме интерпретатора. и собирай на месте хоть франкенштейна из 10 разных классов 🙂
Почему детсадовский? Если несколько копий функции будет писать не программист, а компилятор, то почему бы и нет?
у тебя ран-тайм полиморфизм
done
>>2)Используется шаблон, значит компиль будет инлайнить.
А в результате - приведение типов через reinterpret_cast, нельзя создать массив полиморфных объектов без е..ли и вообще грязь в коде. Смысл?
вызовы функций через указатели не инлайнятся. более того, если на функцию создатся хотя бы один указатель, она вообще не может инлайнится
-точно, а я то думаю, кого он мне напоминает
-но зато он самый быстрый, сильный и гибкий
но чуть ты оплашаешь - обязательно упадешь на большой скорости вниз под копыта
приготовься и запасись терпением. пройдет много времени, прежде чем он тебя зауважает и ты почувствуешь себя его хозяином
анон, ты немного уныл, вернись на сосач
См Static polymorphism в
для виртуальных функций:
первый указатель: указатель на объект (он есть, даже если объект создан в стеке)
второй указатель на VTBL (таблицу виртуальных методов)
третий указатель на виртуальный метод
для не виртуальных методов:
тупо вызывается метод, с зафиксированным константным адресом в опкоде комманды call, что намного быстрее для вызова, даже чем через обычный 1 указатель.
Меня ещё смущает как удалось вызвать приватный метод.
впрочему похуй. кто в теме и так знает, а кто не в теме, тот не поймет нихуя
По-моему мнению, объяснить вы не смогли, ни простыми, ни сложными словами.
И да, Pimpl — это немного не то.
Можно придумать и другие способы. Например, в виртуальной таблице хранить не указатели, а сами методы (в элементах фиксированного размера). Небольшие поместятся все, для больших — команда перехода (или начало и команда перехода). Увеличение расхода памяти не зависит от числа объектов, и на один уровень косвенности для малых методов меньше (для которых это имеет смысл).
Можно избавиться от указателя на таблицу, если объекты разного типа распределять в разных областях памяти. Тогда тип однозначно определяется указателем (старшими битами). В принципе, это реально организовать даже на современных 64-битных процессорах. С стековыми объектами придётся повозиться (по сути на стеке это будут только прозрачные умные указатели), этот способ больше подходит для Java или C#.
Это понятно. Только вот на си этот метод не к месту. Если пишешь для небольших контроллеров - каждый байт на счету. А тут растраты на пустом месте...
Не имеет смысла усложнять на один процент из-за почти отсутствующей выгоды.
>Если в некоторой иерархии всего один виртуальный метод и не используется rtti, то оверхеда нет и это бесспорная оптимизация.
Ох какая бесспорная... Виртуальных методов обычно или 0 или >=2. Случая с одним просто нет. Обычно, если появляется хоть один метод, то сразу появляется и виртуальный деструктор. А rtti вообще по стандарту языка должен быть, если есть виртуальные методы. А rtti это ещё один указатель\виртуальный метод.
RTTI должен быть, если его используют. А если нет для какой-то иерархии dynamic_cast или typeid, то и не нужен.
Эту оптимизацию и вручную сделать можно, указателем на функцию, но если компилятор сам заметит, приятно.
Если хоть в одном классе данной иерархии он используется, то его придется использовать везде, иначе кастить не получится этот объект.
Если хотя бы в одном классе данной иерархии 2 виртуальные функции, то придется заводить указатель на таблицу виртуальных функций во всей иерархии, иначе кастить также не получится.
А с учетом современных тенденций: один класс предок на всю иерархию программы, например как QObject в QT или System.Object в C#, то эта оптимизация совсем работать не будет.
Сила текущей организации vtbl в объекте в том, что это наиболее эффективное решение, но при этом универсальное, поэтому компилятор очень прост не обременен анализом мелких редких частных случаев, не дающим особого выигрыша в реальных условиях.
А между тем компилятор не сможет оценить всю иерархию классов, тк часть классов используется в одной единице трансляций, а часть в другой. А это уже медленный глобальный анализ всего кода всех obj файлов. Линкер повесится, не смотря на то, что это не его работа.
Вопрос межмодульного анализа и оптимизации до сих пор почти не решен ни в одном языке., тк это пока не по зубам современным компьютерам из-за ограничения производительности.
Если вам что-то не нравится, то напишите свой компилятор или вы знаете, где найти assembler и ansi C для экономии на редко встречающихся спичках в своих программах.
Некоторые способы оптимизации (например, dynamic_cast за O(1)) требуют знание о всей иерархии классов. Сейчас компилятор и редактор связей намного умнее, чем были 30 лет назад.
Я - нет, но QT все время. Выигрыш от метода теряется полностью на всех классах QT приложения.
>Сейчас компилятор и редактор связей намного умнее
Вот только не надо. Вижу я этот "ум и гениальность" межмодульной оптимизации каждый день, особенно в GCC или MSVC... И это при часовых компиляциях. А что будет, если добавить ещё больше "ума" межмодульному оптимизатору?
Не подходит С++ для нормальной межмодульной оптимизации., особенно с его препроцессором и включаемыми файлами. 2 этих фактора нарушают легкость межмодульной оптимизации. Компилятору приходится генерировать код, не нарушающий ODR (я про ODR машинного уровня, а не уровня кода), что не так просто, если сделать его "сильно умным" и при этом ошибиться хоть где-нибудь.
Ну и говорить нечего тогда. За чем тогда в спор ввязались? С этим не сталкивались... Этого не знаете... Этого не умеете... и тд...
>Да вы можете использовать классы вообще без виртуальных методов
Спасибо, за разрешение.
Зато есть стандарт де факто и его также желательно поддерживать. Иначе под туже винду нельзя будет легко писать, ибо там COM в моде, особенно с выходом "ЭпикВин8".
Вообщем, терять совместимость из-за копеечных сомнительных оптимизаций при усложнении компиля - не вариант.
Может для вас это секрет, но все компиляторы до конца не совместимы со стандартом.
>Всё равно ведь для того, чтобы сделать COM, нужны дополнительные действия
На GCC или ANSI C в легкую делается COM не выходя за пределы языка.
>Может быть нужны будут специальные подсказки компилятору (прагмы),
Костылей и так хватает. Нечего добавлять новые.
Все уже продумано и во всю используется. Почитайте хотя бы про COM, ABI, что б хоть представлять что это такое. Я уже говорил про стандарт де факто, который вы так хотите нарушить.
Кстати, оно в отрицательном смещении таблицы VTBL.
Не кэшфрендли.
Ещё один недостаток — увеличивается время создания объекта (нужно проинициализировать все указатели на методы).
Тогда и предлагать нечего.
>И продолжает использоваться и поддерживаться сейчас.
примеры?
Я и так знаю, что он использовался при царе горохе. Но это не серьёзно. Не зря же пришли к VTBL.
Что за капитанство? Qtшные классы во внутреннем устройстве не имеют никакого то отклонения от стандарта де факто, использующего VTBL. Все компилится и обычным С++ компилем + кодогенератором препроцессорного типа. Ничего менять в устройстве класса из-за QT не нужно и никто этого не делает.
>это так есть.
Я ещё раз спрашиваю примеры?
>Полагаю
Нечего полагать. Я жду фактов или объяснения большей оптимальности или необходимости такого метода.
Компилируется Qt не обычным компилятором C++, используются свои расширения языка, которые уже компилируются в C++. Напомню, что первый компилятор C++ компилировал в C.
Это проблемы этой библиотеки. К реализации виртуальных методов в языке - GUI-библиотеки не имеют никакого отношения. И если вы и говорите, что эта реализация медленная, так зачем предлагать её в качестве оптимизации для компилятора С++?
>Компилируется Qt не обычным компилятором C++
Я уже сказал, что QT проги компилируется обычным компилятором С++, предварительно прогнав код через кодогенератор препроцессорного типа. Теперь понятно, почему аргументы не доходят до вас и вы продолжаете без конца повторять одно и тоже. Если вы не внимательно читаете, то я не могу ничем вам помочь. Я не могу читать за вас. Видимо, это сигнал мне закончить разговор с вами.
Это вообще не слабое разбухание кода для очень разветвленных иерархий. Придется на каждый отдельный класс хранить свою таблицу кода абсолютно одинаковых функций.
А таких классов может быть много, не забывайте обо всех потомках и предках этого класса в иерархии с перекрывающими методами. А это много классов с абсолютно одинаковыми копиями методов. Особенно эпичный фейл ждет, если вспомнить современные тенденции к кодогенерации и шаблонам, то это уже будет нереально много классов с абсолютно одинаковыми копиями методов.
И вообще это не кешфрендли.
Хватит предлагать методы, что не подходят современным реалиям, а использовались разве что отцами.
Кстати, о кеше. Если разделять кеш для данных и кода, то код пары десятков классов осядет в кеше, а вот vtable с указателями будет постоянно выталкиваться из него обрабатываемыми данными. Но это частности.
А может быть, да кабы, да во рту выросли грибы. Из-за кодогенерации и шаблононов С++ классов очень много. Не хочу иметь дубликат всех функций map для каждой комбинации его шаблонных параметров. Проект и так долго компилируется, а тут ещё и кучу дубликатов. Полумеры не рулят. Ещё этот метод заставляет вставлять лишние джампы в конце каждой большой функции из таблицы, что также не кешфрендли.
>а вот vtable с указателями будет постоянно выталкиваться из него обрабатываемыми данными
Да ладно? Обычно виртуальные функции используются часто, так что не будет выталкиваться.
>от 32 до сотни байт, а самих объектов — миллионы
Эта задача - ещё один сферический кот в вакууме, которых вы так любите приводить в качестве примеров.
>Если компилятор, пошуршав несколько часов, выдаст бинарник, который просчитывает задачу на 20% быстрее, — честь ему и хвала.
Чтобы получить приличный прирост к производительности - нужно оптимизировать алгоритм, а не экономить на спичках (на инструкциях). Компилятор за вас говноалгоритм не перепишет. Если же вам нужна экономия на спичках, я уже сказал, где её найти (Си\асм).
Джамп (только не в конце, а в начале-середине) больших функций как раз соответствует текущей модели vtable.
Ну что поделать, вот с такими сферическими конями приходится иметь дело. Это комы да дотнеты для меня экзотика.
Писать такое на Си или, тем более, ассемблере — безумие, код засорится и помешает высокоуровневой оптимизации. А вот если компилятор бесплатно и прозрачно её проведёт, то можно на такие детали не обращать внимания и заняться алгоритмами.
Поэтому и не было смысла вводить эту оптимизацию. Если вспомнить все вышеперечисленные её недостатки.
>std::map не имеет виртуальных методов.
Ага, а все пользуются только им и шаблонных классов с виртуальными методами не используют. Ну-ну...
>можно на такие детали не обращать внимания и заняться алгоритмами.
Вот и займитесь этим наконец. Не нужно валить все беды с больной головы на здоровую. Нечего обвинять компилятор во всех грехах. Если что-то тормозит - программист написал плохой код и использовал плохой алгоритм. Из-за вашей экономии на спичках прироста не будет, а как мы выяснили уже - одни беды.
Хаки какие то. Это особенно поможет, когда предков у класса 100500. Заведем бесконечное адресное пространство и будем перед каждым вызовом виртуальных функций делать побитовые операции (мега оптимизация) и не понятно как потом определять, какой виртуальный метод вызвать. При этом со стеком в С++ этот метод ждет фейл и тормоза, тк нужно дергать медленный менеджер памяти, а не быстрый стек. И да, придется сделать "особый магический" менеджер памяти для размещения в разных адресах адресного пространства, предварительно переписав ОС, чтобы та позволяла 100% разместить все объекты по конкретным адресам и быстро. А когда адресное пространство с данным битом заполнится до отказу объектами данного типа, программу ждет bad_alloc при почти пустой памяти, а программиста батхерт. Нечего было создавать так много объектов данного типа! Особенно забатхертятся программисты под DOS. Эпичный пафос и пафосный эпос. (:
fix
DOS? 64-битный DOS?
А по вашему GCC не должен компилировать под DOS или под микроконтроллеры? А то что этот метод не совместим с текущими отлаженными бекендами вас не смущает? А то что этот метод не совместим с текущим стандартом С++, например с кастомными аллокаторами или перегрузкой операторов С++ вас тоже не смущает? А то что это метод сильно замедляет работу со стековыми объектами, взамен мелкой экономии на спичках - вас это также не смущает? А то, что винда не позволяет выделять с гарантией по конкретным адресам объекты и может выделить при этом без смущения по другим? С системой куч винды это не совместимо. И тем более винда не позволяет выделять память по заданным регионам? Вас не смущает, что оси придется переписывать. А не смущает ли вас, что в разных версиях осей какие то диапазоны заняты под системные объекты полностью и не доступны для выделения, зато они доступны в других? Придется под каждую ось компилировать отдельно?
Хватит предлагать котов в вакууме.
К перегрузке операторов это не имеет никакого отношения. Работу с автоматическими переменными практически не замедлит (в той же области видимости всё равно виртуальность исчезнет). Как там в виде не знаю, это её проблема, ну значит будут под неё программы медленнее. А так ведь можно отмапить максимально возможное адресное пространство и использовать по своему усмотрению. Не думал, что в современных ОС прикладные программы работают с физической памятью и по абсолютным адресам. Ну да это проблемы этих ОС (кстати, обычно программы таки компилируются отдельно под разные ОС и под разное железо, иногда даже разными компиляторами).
Мне интересно, где вы его взяли? А С++ компилятор должен компилировать и под DOS и под МК, но я вам уже это говорил. Но видимо, для вас нужно много раз повторить, прежде чем дойдет.
>И почему вы против архитектурно-специфичных оптимизаций?
Вот когда поработаете над кроссплатформенными проектами, тогда и поговорим. См ниже.
>К перегрузке операторов это не имеет никакого отношения.
Да ладно? А как же вы через стандартный malloc затребуете память по определенному региону? Если это архитектуро-специфичная "оптимизация", то как же вы будете перегружать оператор new? Под одну платформу с использованием регионов, а под другую без? Решили добавить ещё одну причину писать программисту дубликаты кода под разные платформы? Обойдемся.
>Работу с автоматическими переменными практически не замедлит.
Замедлит и ещё как. В стеке память выделяется за одну инструкцию проца, а вы предлагаете вызывать тормозную кучу с очень большим не детерминированным временем выделения и освобождения памяти. А между тем автоматических объектов в С++ большинство в среднестатистической программе. "Хорошая" оптимизация у вас получилась...
То, что винда не поддерживают распределение по регионам - это точно. Аналогично и в других осях. Это гениальная идея - переписать винду под С++ с вашей мегооптимизацией. Атцы одобрят.
>Ну да это проблемы этих ОС
По моему эта ваша личная проблема и пользователей вашего "компилятора".
>Не думал
Знаю.
Это (а также другие ваши реплики) показывает, что вы совершенно не слушаете собеседника, а значит продолжать эту дискуссию бессмысленно. А с учётом вашего тона — и нежелательно.
Это вы зачем то приплели 64-битные машины с виртуальной страничной памятью, когда мы говорим про мультиплатформенный С++, работающий почти везде.
>вы совершенно не слушаете собеседника, а значит продолжать эту дискуссию бессмысленно
Аналогично, я про вас это уже сказал и повторятся не буду.
Надо быть сдержаннее. (:
Я один заметил, что зарезервированное слово используется в качестве идентификатора?
А я думал, он должен скомпилировать и убить брата
дельфи штоле?