+155
- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
#include <iostream>
#include <memory>
#include <assert.h>
using namespace std;
template <class T>
class megaClass
{
public:
void hello()
{
assert(dynamic_cast<T*>(this)!=NULL);
static_cast<T*>(this)->hello();
}
virtual ~megaClass() {}
};
class cleft : public megaClass<cleft>
{
public:
void hello()
{
std::cout << "left::hello()" << std::endl;
}
};
class cright : public megaClass<cright>
{
public:
void hello()
{
std::cout << "right::hello()" << std::endl;
}
};
int main()
{
scoped_ptr<megaClass<cleft> > a1=new cleft;
a1->hello();
scoped_ptr<megaClass<cright> > a2=new cright;
a2->hello();
return 0;
}
Пытался продемонстрировать статический полиморфизм 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)Если понадобится резкой перейти от статического полиморфизма к динамическому - придётся переписывать на виртуальные функции или на истинный статический полиморфизм.
Обсуждения здесь:
http://govnokod.ru/8025#comment110773
Сразу исключим детсадовский вариант статического функционального полиморфизма c перегрузкой функций:Class1 o1;
foo(o1);
Class2 o2;
foo(o2);
void foo(Class1 o){/*...*/};
void foo(Class2 o){/*...*/};
Кто-нибудь реально умеет can into нормальный статический полиморфизм?
Запостил: CPPGovno,
30 Сентября 2011
Govnoeb 30.09.2011 13:21 # 0
CPPGovno 30.09.2011 13:22 # 0
Govnoeb 30.09.2011 13:32 # 0
CKrestKrestGovno 30.09.2011 15:03 # +2
Govnoeb 01.10.2011 17:44 # 0
absolut 01.10.2011 20:08 # +2
TarasB 30.09.2011 13:24 # 0
Почему детсадовский? Если несколько копий функции будет писать не программист, а компилятор, то почему бы и нет?
gegMOPO4 30.09.2011 13:34 # +3
Govnoeb 30.09.2011 13:36 # +6
absolut 30.09.2011 14:32 # 0
roman-kashitsyn 30.09.2011 14:38 # +13
absolut 30.09.2011 14:57 # +3
CKrestKrestGovno 30.09.2011 15:05 # 0
absolut 30.09.2011 15:06 # +3
SmackMyBitchUp 30.09.2011 16:34 # 0
gammaker 01.10.2011 12:27 # 0
CPPGovno 01.10.2011 14:57 # 0
CPPGovno 01.10.2011 14:54 # 0
istem 30.09.2011 16:36 # +6
gegMOPO4 30.09.2011 19:20 # +1
CPPGovno 30.09.2011 20:21 # 0
Xom94ok 30.09.2011 20:23 # 0
Govnoeb 01.10.2011 17:48 # +1
у тебя ран-тайм полиморфизм
Xom94ok 02.10.2011 06:51 # 0
done
>>2)Используется шаблон, значит компиль будет инлайнить.
А в результате - приведение типов через reinterpret_cast, нельзя создать массив полиморфных объектов без е..ли и вообще грязь в коде. Смысл?
Govnoeb 02.10.2011 08:55 # 0
вызовы функций через указатели не инлайнятся. более того, если на функцию создатся хотя бы один указатель, она вообще не может инлайнится
Xom94ok 02.10.2011 09:32 # 0
CPPGovno 30.09.2011 22:42 # 0
-точно, а я то думаю, кого он мне напоминает
-но зато он самый быстрый, сильный и гибкий
но чуть ты оплашаешь - обязательно упадешь на большой скорости вниз под копыта
приготовься и запасись терпением. пройдет много времени, прежде чем он тебя зауважает и ты почувствуешь себя его хозяином
bugmenot 01.10.2011 18:21 # +4
CPPGovno 01.10.2011 20:23 # +1
bugmenot 01.10.2011 20:25 # −2
CPPGovno 01.10.2011 20:26 # +1
bugmenot 01.10.2011 20:28 # −1
анон, ты немного уныл, вернись на сосач
CPPGovno 01.10.2011 20:34 # +1
bugmenot 01.10.2011 23:10 # 0
CPPGovno 02.10.2011 12:36 # +2
CPPGovno 01.10.2011 20:06 # 0
См Static polymorphism в
CPPGovno 01.10.2011 20:10 # 0
CPPGovno 01.10.2011 20:22 # −3
CPPGovno 02.10.2011 11:44 # −2
для виртуальных функций:
первый указатель: указатель на объект (он есть, даже если объект создан в стеке)
второй указатель на VTBL (таблицу виртуальных методов)
третий указатель на виртуальный метод
для не виртуальных методов:
тупо вызывается метод, с зафиксированным константным адресом в опкоде комманды call, что намного быстрее для вызова, даже чем через обычный 1 указатель.
Govnoeb 02.10.2011 14:32 # −2
gegMOPO4 02.10.2011 16:02 # +2
absolut 02.10.2011 16:05 # +4
Меня ещё смущает как удалось вызвать приватный метод.
Govnoeb 02.10.2011 18:26 # −1
впрочему похуй. кто в теме и так знает, а кто не в теме, тот не поймет нихуя
SmackMyBitchUp 03.10.2011 17:23 # 0
По-моему мнению, объяснить вы не смогли, ни простыми, ни сложными словами.
gegMOPO4 02.10.2011 16:05 # +2
И да, Pimpl — это немного не то.
TarasB 03.10.2011 11:49 # 0
CPPGovno 03.10.2011 13:30 # 0
gegMOPO4 03.10.2011 14:05 # 0
CKrestKrestGovno 03.10.2011 17:38 # 0
gegMOPO4 03.10.2011 20:42 # 0
Можно придумать и другие способы. Например, в виртуальной таблице хранить не указатели, а сами методы (в элементах фиксированного размера). Небольшие поместятся все, для больших — команда перехода (или начало и команда перехода). Увеличение расхода памяти не зависит от числа объектов, и на один уровень косвенности для малых методов меньше (для которых это имеет смысл).
Можно избавиться от указателя на таблицу, если объекты разного типа распределять в разных областях памяти. Тогда тип однозначно определяется указателем (старшими битами). В принципе, это реально организовать даже на современных 64-битных процессорах. С стековыми объектами придётся повозиться (по сути на стеке это будут только прозрачные умные указатели), этот способ больше подходит для Java или C#.
CPPGovno 03.10.2011 22:14 # 0
Это понятно. Только вот на си этот метод не к месту. Если пишешь для небольших контроллеров - каждый байт на счету. А тут растраты на пустом месте...
gegMOPO4 04.10.2011 08:37 # 0
CKrestKrestGovno 05.10.2011 15:21 # 0
CPPGovno 03.10.2011 22:19 # 0
gegMOPO4 04.10.2011 08:40 # 0
CKrestKrestGovno 04.10.2011 15:11 # 0
Не имеет смысла усложнять на один процент из-за почти отсутствующей выгоды.
gegMOPO4 04.10.2011 15:53 # 0
CPPGovno 05.10.2011 00:15 # 0
>Если в некоторой иерархии всего один виртуальный метод и не используется rtti, то оверхеда нет и это бесспорная оптимизация.
Ох какая бесспорная... Виртуальных методов обычно или 0 или >=2. Случая с одним просто нет. Обычно, если появляется хоть один метод, то сразу появляется и виртуальный деструктор. А rtti вообще по стандарту языка должен быть, если есть виртуальные методы. А rtti это ещё один указатель\виртуальный метод.
gegMOPO4 05.10.2011 09:22 # 0
RTTI должен быть, если его используют. А если нет для какой-то иерархии dynamic_cast или typeid, то и не нужен.
Эту оптимизацию и вручную сделать можно, указателем на функцию, но если компилятор сам заметит, приятно.
CPPGovno 05.10.2011 13:17 # 0
Если хоть в одном классе данной иерархии он используется, то его придется использовать везде, иначе кастить не получится этот объект.
Если хотя бы в одном классе данной иерархии 2 виртуальные функции, то придется заводить указатель на таблицу виртуальных функций во всей иерархии, иначе кастить также не получится.
А с учетом современных тенденций: один класс предок на всю иерархию программы, например как QObject в QT или System.Object в C#, то эта оптимизация совсем работать не будет.
Сила текущей организации vtbl в объекте в том, что это наиболее эффективное решение, но при этом универсальное, поэтому компилятор очень прост не обременен анализом мелких редких частных случаев, не дающим особого выигрыша в реальных условиях.
А между тем компилятор не сможет оценить всю иерархию классов, тк часть классов используется в одной единице трансляций, а часть в другой. А это уже медленный глобальный анализ всего кода всех obj файлов. Линкер повесится, не смотря на то, что это не его работа.
Вопрос межмодульного анализа и оптимизации до сих пор почти не решен ни в одном языке., тк это пока не по зубам современным компьютерам из-за ограничения производительности.
Если вам что-то не нравится, то напишите свой компилятор или вы знаете, где найти assembler и ansi C для экономии на редко встречающихся спичках в своих программах.
gegMOPO4 05.10.2011 14:19 # 0
Некоторые способы оптимизации (например, dynamic_cast за O(1)) требуют знание о всей иерархии классов. Сейчас компилятор и редактор связей намного умнее, чем были 30 лет назад.
CKrestKrestGovno 05.10.2011 14:59 # 0
Я - нет, но QT все время. Выигрыш от метода теряется полностью на всех классах QT приложения.
>Сейчас компилятор и редактор связей намного умнее
Вот только не надо. Вижу я этот "ум и гениальность" межмодульной оптимизации каждый день, особенно в GCC или MSVC... И это при часовых компиляциях. А что будет, если добавить ещё больше "ума" межмодульному оптимизатору?
Не подходит С++ для нормальной межмодульной оптимизации., особенно с его препроцессором и включаемыми файлами. 2 этих фактора нарушают легкость межмодульной оптимизации. Компилятору приходится генерировать код, не нарушающий ODR (я про ODR машинного уровня, а не уровня кода), что не так просто, если сделать его "сильно умным" и при этом ошибиться хоть где-нибудь.
gegMOPO4 05.10.2011 21:11 # 0
CPPGovno 05.10.2011 22:52 # −1
Ну и говорить нечего тогда. За чем тогда в спор ввязались? С этим не сталкивались... Этого не знаете... Этого не умеете... и тд...
>Да вы можете использовать классы вообще без виртуальных методов
Спасибо, за разрешение.
CPPGovno 03.10.2011 22:23 # 0
gegMOPO4 04.10.2011 08:45 # +1
CKrestKrestGovno 04.10.2011 15:13 # 0
Зато есть стандарт де факто и его также желательно поддерживать. Иначе под туже винду нельзя будет легко писать, ибо там COM в моде, особенно с выходом "ЭпикВин8".
gegMOPO4 04.10.2011 15:55 # 0
CPPGovno 05.10.2011 00:23 # 0
Вообщем, терять совместимость из-за копеечных сомнительных оптимизаций при усложнении компиля - не вариант.
gegMOPO4 05.10.2011 09:45 # 0
CPPGovno 05.10.2011 13:24 # 0
Может для вас это секрет, но все компиляторы до конца не совместимы со стандартом.
>Всё равно ведь для того, чтобы сделать COM, нужны дополнительные действия
На GCC или ANSI C в легкую делается COM не выходя за пределы языка.
>Может быть нужны будут специальные подсказки компилятору (прагмы),
Костылей и так хватает. Нечего добавлять новые.
gegMOPO4 05.10.2011 14:24 # 0
CKrestKrestGovno 05.10.2011 14:50 # 0
gegMOPO4 05.10.2011 21:14 # 0
CPPGovno 05.10.2011 22:48 # −1
Все уже продумано и во всю используется. Почитайте хотя бы про COM, ABI, что б хоть представлять что это такое. Я уже говорил про стандарт де факто, который вы так хотите нарушить.
guest 07.10.2011 17:18 # 0
Кстати, оно в отрицательном смещении таблицы VTBL.
roman-kashitsyn 07.10.2011 17:24 # 0
guest 07.10.2011 18:46 # −3
3.14159265 07.10.2011 21:07 # +1
guest 07.10.2011 22:21 # −3
CPPGovno 05.10.2011 00:24 # 0
Не кэшфрендли.
gegMOPO4 05.10.2011 09:48 # 0
Ещё один недостаток — увеличивается время создания объекта (нужно проинициализировать все указатели на методы).
CPPGovno 05.10.2011 13:27 # 0
Тогда и предлагать нечего.
>И продолжает использоваться и поддерживаться сейчас.
примеры?
Я и так знаю, что он использовался при царе горохе. Но это не серьёзно. Не зря же пришли к VTBL.
gegMOPO4 05.10.2011 14:28 # 0
CKrestKrestGovno 05.10.2011 14:48 # 0
Что за капитанство? Qtшные классы во внутреннем устройстве не имеют никакого то отклонения от стандарта де факто, использующего VTBL. Все компилится и обычным С++ компилем + кодогенератором препроцессорного типа. Ничего менять в устройстве класса из-за QT не нужно и никто этого не делает.
>это так есть.
Я ещё раз спрашиваю примеры?
>Полагаю
Нечего полагать. Я жду фактов или объяснения большей оптимальности или необходимости такого метода.
gegMOPO4 05.10.2011 21:24 # 0
Компилируется Qt не обычным компилятором C++, используются свои расширения языка, которые уже компилируются в C++. Напомню, что первый компилятор C++ компилировал в C.
CPPGovno 05.10.2011 22:54 # −1
Это проблемы этой библиотеки. К реализации виртуальных методов в языке - GUI-библиотеки не имеют никакого отношения. И если вы и говорите, что эта реализация медленная, так зачем предлагать её в качестве оптимизации для компилятора С++?
>Компилируется Qt не обычным компилятором C++
Я уже сказал, что QT проги компилируется обычным компилятором С++, предварительно прогнав код через кодогенератор препроцессорного типа. Теперь понятно, почему аргументы не доходят до вас и вы продолжаете без конца повторять одно и тоже. Если вы не внимательно читаете, то я не могу ничем вам помочь. Я не могу читать за вас. Видимо, это сигнал мне закончить разговор с вами.
CPPGovno 05.10.2011 00:29 # 0
Это вообще не слабое разбухание кода для очень разветвленных иерархий. Придется на каждый отдельный класс хранить свою таблицу кода абсолютно одинаковых функций.
gegMOPO4 05.10.2011 10:01 # 0
CPPGovno 05.10.2011 13:35 # 0
А таких классов может быть много, не забывайте обо всех потомках и предках этого класса в иерархии с перекрывающими методами. А это много классов с абсолютно одинаковыми копиями методов. Особенно эпичный фейл ждет, если вспомнить современные тенденции к кодогенерации и шаблонам, то это уже будет нереально много классов с абсолютно одинаковыми копиями методов.
И вообще это не кешфрендли.
Хватит предлагать методы, что не подходят современным реалиям, а использовались разве что отцами.
gegMOPO4 05.10.2011 14:45 # 0
Кстати, о кеше. Если разделять кеш для данных и кода, то код пары десятков классов осядет в кеше, а вот vtable с указателями будет постоянно выталкиваться из него обрабатываемыми данными. Но это частности.
CKrestKrestGovno 05.10.2011 15:11 # 0
А может быть, да кабы, да во рту выросли грибы. Из-за кодогенерации и шаблононов С++ классов очень много. Не хочу иметь дубликат всех функций map для каждой комбинации его шаблонных параметров. Проект и так долго компилируется, а тут ещё и кучу дубликатов. Полумеры не рулят. Ещё этот метод заставляет вставлять лишние джампы в конце каждой большой функции из таблицы, что также не кешфрендли.
>а вот vtable с указателями будет постоянно выталкиваться из него обрабатываемыми данными
Да ладно? Обычно виртуальные функции используются часто, так что не будет выталкиваться.
>от 32 до сотни байт, а самих объектов — миллионы
Эта задача - ещё один сферический кот в вакууме, которых вы так любите приводить в качестве примеров.
>Если компилятор, пошуршав несколько часов, выдаст бинарник, который просчитывает задачу на 20% быстрее, — честь ему и хвала.
Чтобы получить приличный прирост к производительности - нужно оптимизировать алгоритм, а не экономить на спичках (на инструкциях). Компилятор за вас говноалгоритм не перепишет. Если же вам нужна экономия на спичках, я уже сказал, где её найти (Си\асм).
gegMOPO4 05.10.2011 21:35 # 0
Джамп (только не в конце, а в начале-середине) больших функций как раз соответствует текущей модели vtable.
Ну что поделать, вот с такими сферическими конями приходится иметь дело. Это комы да дотнеты для меня экзотика.
Писать такое на Си или, тем более, ассемблере — безумие, код засорится и помешает высокоуровневой оптимизации. А вот если компилятор бесплатно и прозрачно её проведёт, то можно на такие детали не обращать внимания и заняться алгоритмами.
CPPGovno 05.10.2011 22:32 # 0
Поэтому и не было смысла вводить эту оптимизацию. Если вспомнить все вышеперечисленные её недостатки.
>std::map не имеет виртуальных методов.
Ага, а все пользуются только им и шаблонных классов с виртуальными методами не используют. Ну-ну...
>можно на такие детали не обращать внимания и заняться алгоритмами.
Вот и займитесь этим наконец. Не нужно валить все беды с больной головы на здоровую. Нечего обвинять компилятор во всех грехах. Если что-то тормозит - программист написал плохой код и использовал плохой алгоритм. Из-за вашей экономии на спичках прироста не будет, а как мы выяснили уже - одни беды.
CPPGovno 05.10.2011 00:42 # 0
Хаки какие то. Это особенно поможет, когда предков у класса 100500. Заведем бесконечное адресное пространство и будем перед каждым вызовом виртуальных функций делать побитовые операции (мега оптимизация) и не понятно как потом определять, какой виртуальный метод вызвать. При этом со стеком в С++ этот метод ждет фейл и тормоза, тк нужно дергать медленный менеджер памяти, а не быстрый стек. И да, придется сделать "особый магический" менеджер памяти для размещения в разных адресах адресного пространства, предварительно переписав ОС, чтобы та позволяла 100% разместить все объекты по конкретным адресам и быстро. А когда адресное пространство с данным битом заполнится до отказу объектами данного типа, программу ждет bad_alloc при почти пустой памяти, а программиста батхерт. Нечего было создавать так много объектов данного типа! Особенно забатхертятся программисты под DOS. Эпичный пафос и пафосный эпос. (:
CPPGovno 05.10.2011 05:44 # 0
fix
gegMOPO4 05.10.2011 10:14 # 0
DOS? 64-битный DOS?
CKrestKrestGovno 05.10.2011 14:40 # 0
А по вашему GCC не должен компилировать под DOS или под микроконтроллеры? А то что этот метод не совместим с текущими отлаженными бекендами вас не смущает? А то что этот метод не совместим с текущим стандартом С++, например с кастомными аллокаторами или перегрузкой операторов С++ вас тоже не смущает? А то что это метод сильно замедляет работу со стековыми объектами, взамен мелкой экономии на спичках - вас это также не смущает? А то, что винда не позволяет выделять с гарантией по конкретным адресам объекты и может выделить при этом без смущения по другим? С системой куч винды это не совместимо. И тем более винда не позволяет выделять память по заданным регионам? Вас не смущает, что оси придется переписывать. А не смущает ли вас, что в разных версиях осей какие то диапазоны заняты под системные объекты полностью и не доступны для выделения, зато они доступны в других? Придется под каждую ось компилировать отдельно?
Хватит предлагать котов в вакууме.
gegMOPO4 05.10.2011 21:50 # +1
К перегрузке операторов это не имеет никакого отношения. Работу с автоматическими переменными практически не замедлит (в той же области видимости всё равно виртуальность исчезнет). Как там в виде не знаю, это её проблема, ну значит будут под неё программы медленнее. А так ведь можно отмапить максимально возможное адресное пространство и использовать по своему усмотрению. Не думал, что в современных ОС прикладные программы работают с физической памятью и по абсолютным адресам. Ну да это проблемы этих ОС (кстати, обычно программы таки компилируются отдельно под разные ОС и под разное железо, иногда даже разными компиляторами).
CPPGovno 05.10.2011 22:24 # −1
Мне интересно, где вы его взяли? А С++ компилятор должен компилировать и под DOS и под МК, но я вам уже это говорил. Но видимо, для вас нужно много раз повторить, прежде чем дойдет.
>И почему вы против архитектурно-специфичных оптимизаций?
Вот когда поработаете над кроссплатформенными проектами, тогда и поговорим. См ниже.
>К перегрузке операторов это не имеет никакого отношения.
Да ладно? А как же вы через стандартный malloc затребуете память по определенному региону? Если это архитектуро-специфичная "оптимизация", то как же вы будете перегружать оператор new? Под одну платформу с использованием регионов, а под другую без? Решили добавить ещё одну причину писать программисту дубликаты кода под разные платформы? Обойдемся.
>Работу с автоматическими переменными практически не замедлит.
Замедлит и ещё как. В стеке память выделяется за одну инструкцию проца, а вы предлагаете вызывать тормозную кучу с очень большим не детерминированным временем выделения и освобождения памяти. А между тем автоматических объектов в С++ большинство в среднестатистической программе. "Хорошая" оптимизация у вас получилась...
То, что винда не поддерживают распределение по регионам - это точно. Аналогично и в других осях. Это гениальная идея - переписать винду под С++ с вашей мегооптимизацией. Атцы одобрят.
>Ну да это проблемы этих ОС
По моему эта ваша личная проблема и пользователей вашего "компилятора".
>Не думал
Знаю.
gegMOPO4 05.10.2011 22:47 # +3
Это (а также другие ваши реплики) показывает, что вы совершенно не слушаете собеседника, а значит продолжать эту дискуссию бессмысленно. А с учётом вашего тона — и нежелательно.
guest 07.10.2011 22:16 # 0
Это вы зачем то приплели 64-битные машины с виртуальной страничной памятью, когда мы говорим про мультиплатформенный С++, работающий почти везде.
>вы совершенно не слушаете собеседника, а значит продолжать эту дискуссию бессмысленно
Аналогично, я про вас это уже сказал и повторятся не буду.
guest 07.10.2011 22:18 # 0
Надо быть сдержаннее. (:
SmackMyBitchUp 06.10.2011 21:48 # 0
Xom94ok 02.10.2011 09:34 # +2
Я один заметил, что зарезервированное слово используется в качестве идентификатора?
CPPGovno 02.10.2011 10:10 # 0
Xom94ok 02.10.2011 12:31 # 0
SmackMyBitchUp 02.10.2011 13:37 # +1
А я думал, он должен скомпилировать и убить брата
CPPGovno 02.10.2011 13:58 # 0
Uhehesh 02.10.2011 13:59 # −4
Xom94ok 02.10.2011 14:58 # −3
bugmenot 02.10.2011 16:52 # 0
дельфи штоле?
CPPGovno 02.10.2011 18:55 # 0
SmackMyBitchUp 02.10.2011 20:35 # +5
rst256 31.12.2014 12:43 # 0
guest8 09.04.2019 11:38 # −999