вторник, 26 июня 2012 г.

О страшном и ужасном

Хотел было назвать пост "О великом и могучем", но не решился.

Моя речь пойдет о формальном С++, плоском С, и еще кое о чем.

Знакомство ограничивалось спортивными задачами (размерами в несколько Кб), и двумя-тремя проектами в несколько десятков Кб (сущностей по 50). Решил улучшить качество этих проектов, чуть выше коленки.

В свои спортивные годы мы писали скорее на чистом С, без использования stl (максимум использовали bitset). Хеши писали вручную в 3 минуты, qsort тоже самопальный. Может конечно и глупо, но хватало. Времена такие были.

Коротко, что я узнал за последние недели.
- ссылки. Это показывает мой нулевой уровень. Ссылки - это те же самые указатели, только с сахаром и не пустые.

- раздельная компиляция, makefile. Все равно это медленно работает. Как сказал Андрей Б. из JB: "есть куча медленно компилируемых языков. Например, есть язык, название которого начинается на "С" а заканчивается на "плюс плюс".

- как это компилируется и линкуется.  С другими платформами/языками обычно адекватно ругается компилятор. Тут же можно заниматься непристойными вещами не только с компилятором, но и с линкером. Адекватности в сообщениях об ошибках замечено не было, больше похоже на черный ящик.

- куча мелких фишек. Есть даже фишки, которые работают, только если в классе есть виртуальные функции. В этом случае компилятор что-то дописывает (в ином случае так все компилируется, что вы никогда не узнаете, что у вас были объекты). В последний стандарт так и не вошли штуки из boost.reflection, подозреваю, что там куча макросов которые пародируют рефлексию.

- перегрузка операторов. Оказывается, (->) и (*) тоже можно перегрузить. Так они сделали "умные указатели". Внезапно. [] тоже переопределяется, но это не get/set как в C#; тут в одну сторону, обычно возвращается ссылка. Обновить всю структуру может быть затруднительно. Создавать свои операторы язык как-то не позволяет, это вам, блин, не Haskell.

Оказывается в плоском С можно почти моделировать исключения. Есть низкоуровневая функция, которая запоминает положение текущей команды/инструкции. Затем мы вызываем функцию, еще функцию, а затем можем продолжить с того запомненного места. Низкоуровнево тупо пишем в ip. Если бы я был царицею морскою писал компилятор чего-нибудь с исключениями, то тут можно голову поломать "как быть с типизацией", кидать нужно на один уровень и там как-то обрабатывать. Нетривиальная штука.

Религиозные споры на счет того, надо ++i или же i++. Вот для итераторов желателен прединкремент, подумайте 30 сек зачем. Для простых типов (int) на некоторых(!) архитектурах говорят, что прединкремент на одну/две инструкции быстрее. Я таки считаю, что это пусть компилятор решает, это его задача и в этой области он (компилятор) должен быть умнее программиста. Ставить или нет inline человеку тоже бессмысленно, нормальный компилятор умнее и все сделает за вас.

Темплейты... Далеко не дженерики в современных. Нужны исходники, иначе инстанцировать темплейт не получится, эта штука не компилируется в объектный код. То есть чуть выше #define, да и с их помощи можно много чего натемплейтить. Зато можно копаться в исходниках stl или boost. Ибо, как уже отмечалось, компилируется это медленно.

Указатели на функции были давно. Новые \lambda-функции синтаксически так же уродски, как и все остальное. Но довольно сильные, там еще прикольный механизм связывания переменных.

Вообще, стандарт языка содержит список каких-то библиотек. Что очень странно. Стандарт большой - ему видней.

Говорят, что какой-то магией даже call stack организовывать. Но раз это магия, то такты считать уже будет  не принято.

Плоский С принято хвалить за то, что как написано, так и откомпилируется (плюс-минус пара оптиимизаций). В современных плюсах та же lambda будет компилироваться не_понятно_во_что. Во всяких C# тот же yield/linq и прочие функциональные штучки компилируются нетривиальным образом. Потом дебагерром это даже нормально не отладишь.

auto для плюсов - это просто прорыв. Они до сих пор называют это выводом типа, я все равно плююсь. Но для плюсов это реально прорыв.

valgrind - крутая штука для поиска memory leak, можно как и профайлер. Рекомендую. Очень рекомендую. Очень, очень. (Замыкание по Клини*).

Общее впечатление у меня пока только формируется и сильно undefined behaviour. Если очень нужна скорость (выполнения), то даже использование stl как-то выглядит для меня несколько глупым (про какой-нибудь boost промолчу). Если уже нужно понятие надежности, то явно находимся не в той области. Какая-то грань между скоростью и надежностью... зыбкая... больше к скорости. Видимо, что-то очень большое и больше скорость. Хотя терпимо, втянуться можно.

Комментариев нет: