Мы хотим, что бы нельзя было:
1. вызывать lib_f1/lib_f2, если не вызвали lib_init
2. вызывать lib_deinit, если не вызвали lib_f1/lib_f2 и lib_init
3. не вызвать lib_deinit, если вызывали lib_f1/lib_f2/lib_init
4. вообще ничего не вызывать из заголовка (иначе зачем включали?)
Сразу пример реализации этих требований, что бы не было скучно. С использованием неких вспомогательных классов (которые приведу ниже) эти требования можно записать следующим образом:
Где первый параметр lib_ind — это номер группы, к которой относится функция. В данном случае имеем три группы: группа 0 — функция lib_init, группа 1 — функция деинициализации lib_deinit, группа 2 — "рабочие" функции библиотеки lib_f1/lib_f2.
Последующие параметры lib_ind — номера групп, из которых надо вызвать хотя бы одну функцию перед функциями из данной группы.
С помощью final_check можно задать группы, из которых безусловно должна быть вызвана хотя бы одна функция. В данном случае задаём, что обязательно должна быть вызвана функция lib_deinit (группа 1).
Т.е. таким образом задаём граф корректной последовательности вызовов функций.
Данное описание задаёт следующий порядок вызовов функций:
int main()
{
lib_init();
lib_f1();
lib_f2();
lib_deinit();
}
Любые отклонения от данного порядка не скомпилируются! Если не верите — проверьте, это действительно так.
Далее некоторые замечания:
Задаётся порядок именно упоминаний функций в коде (порядок вызовов в райн-тайм проверить достаточно тривиально). Следовательно скомпилируется следующий (некорректный) код:
И естественно ничего не будет работать, если, например, инициализацию/деинициализацию вызывать в одной единице трансляции, а использовать библиотеку в другой, т.к. все эти проверки работают на уровне одной единицы трансляции.
О практической применимости такой техники в реальной жизни решайте сами.
В защиту могу сказать следующее. Такая техника заставляет:
1. Локализовывать использование библиотеки в одном cpp-файле. Размазывание вызовов по нескольким файлам в общем случае, я бы считал Плохой Вещью.
2. Форсируется использование библиотеки в виде некого заранее известного, корректного и локального паттерна кода. Например так:
int main()
{
lib_init();
lib_f1();
lib_f2();
lib_deinit();
}
Понятно, что можно и корректно использовать библиотеку, если разнести вызовы по разным функциям и перемешать их в хаотическом порядке. Но зачем? Если можно записать их в одной функции и в известном порядке. Т.о. если открыть файл, который видишь первый раз, человека, код которого ни разу не видел, всё равно будешь знать что ожидать.
R>Мы хотим, что бы нельзя было: R>1. вызывать lib_f1/lib_f2, если не вызвали lib_init R>2. вызывать lib_deinit, если не вызвали lib_f1/lib_f2 и lib_init R>3. не вызвать lib_deinit, если вызывали lib_f1/lib_f2/lib_init R>4. вообще ничего не вызывать из заголовка (иначе зачем включали?) R>
Круто конечно, но, почему просто не сделать так:
Кроме пункта 4 — всё выполняется.
Тебе не кажется, что ты изобрёл классы?
Насчёт пункта 4 — оно конечно да, при включении лишнего файла увеличивается время компиляции, но не окажется ли, что эти навороты, если их применять повсеместно, съедят гораздо больше того-же самого времени?
Причём, неиспользуемый заголовок мы таки можем найти и выкинуть, чем избавимся от этих затрат.
А твоя механика будет жрать ресурсы всегда.
Ну и не работает в случае заголовков из которых используются только типы stdint.h например.
Re: [Trick] Форсирование правильного использования библиотек
Здравствуйте, IROV.., Вы писали:
IRO>Здравствуйте, Константин Л., Вы писали:
КЛ>>remark, ды ты маньяк!
IRO>да я бы за такой то код, да по самые гланды!
а ты извращенец
Re[2]: [Trick] Форсирование правильного использования библио
T>Кроме пункта 4 — всё выполняется. T>Тебе не кажется, что ты изобрёл классы?
Класс позволяет задавать только один тип порядка выполнения функций: конструктор -> любые функции-члены -> деструктор.
Предложенный способ позволяет гораздо больший набор, практически произвольный.
T>Насчёт пункта 4 — оно конечно да, при включении лишнего файла увеличивается время компиляции, но не окажется ли, что эти навороты, если их применять повсеместно, съедят гораздо больше того-же самого времени? T>Причём, неиспользуемый заголовок мы таки можем найти и выкинуть, чем избавимся от этих затрат. T>А твоя механика будет жрать ресурсы всегда.
Ты не учёт ещё один важный момент: зависимости между файлами — если у тебя в cpp включён десяток лишних h, то и пересобиратся он будет при изменении этих h'ников. Бывают такие проекты, где пара сотен файлов и они все всегда пересодираются при любом изменении и
T>Ну и не работает в случае заголовков из которых используются только типы stdint.h например.
Для таких заголовков техника не применима... хотя если подумать
Здравствуйте, remark, Вы писали:
R>Здравствуйте, Tonal-, Вы писали:
R>Предложенный способ позволяет гораздо больший набор, практически произвольный.
Класс тоже позволяет произвольный, и не позволяет например такой:
lib_init();
lib_deinit();
lib_deinit();
или такой
lib_init();
lib_deinit();
lib_f1();
Зато позволяет провести корректный повторный цикл.
R>Ты не учёт ещё один важный момент: зависимости между файлами — если у тебя в cpp включён десяток лишних h, то и пересобиратся он будет при изменении этих h'ников. Бывают такие проекты, где пара сотен файлов и они все всегда пересодираются при любом изменении и
Этого можно добиться и в случае если все заголовочники используються.
Тут надо консервоторию править.
T>>Ну и не работает в случае заголовков из которых используются только типы stdint.h например. R>Для таких заголовков техника не применима... хотя если подумать
Не только их.
Что делать с библиотеками классов и шаблонов?
Что делать с библиотеками макросов?
Кроме того, есть техники, основанные на неоднократном включении заголовков см. Flex или Boost.Preprocess.
Ну и кроме того всёж-таки MS...
Хотя, у gсс, насколько я знаю, свои навароты имеються схожей тематики
Re[4]: [Trick] Форсирование правильного использования библио
Здравствуйте, remark, Вы писали:
R>Здравствуйте, Tonal-, Вы писали:
T>>Что делать с библиотеками классов и шаблонов? T>>Что делать с библиотеками макросов? T>>Кроме того...
R>Я не говорил, что этим решением я собираюсь решить все проблемы программирования
Кроме того, конструктивные дополнения приветствуются...
Я показал новое применение старой вещи, открывающее принципиально новые возможности. Если тебе нужно такое решение для библиотек классов и шаблонов и библиотек макросов, давай вместе думать, как это сделать.
R>
О какой библиотеке идёт речь?
— инлайновая
— статическая
— динамическая
Фокус с шаблонами (запрос к линкеру, что именно было использовано хоть где-то) прокатит только для первого случая и только в пределах одной единицы трансляции.
Действительно ли оно надо? Это ведь не просто ограничение. Будут ложные срабатывания, если lib_init делается в одном .cpp, а lib_deinit — в другом.
Может быть, более практично делать проверки в рантайме, написав простенький конечный автомат.
Вот придумать на DSL для определения такого автомата — это было бы прикольно.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[2]: [Trick] Форсирование правильного использования библио
К>О какой библиотеке идёт речь? К>- инлайновая К>- статическая К>- динамическая
Неважно — h'ник будет в любом случае.
К>Фокус с шаблонами (запрос к линкеру, что именно было использовано хоть где-то) прокатит только для первого случая и только в пределах одной единицы трансляции.
Так и есть.
К>Действительно ли оно надо?
Я это и не утверждаю
К>Это ведь не просто ограничение. Будут ложные срабатывания, если lib_init делается в одном .cpp, а lib_deinit — в другом.
Да. Все правильно. Об этом и писал. А зачем разносить работу с библиотекой по разным файлам, если её вполне можно использовать в одном?
Ну опять же, надо к этому правильно относится — как тут один товарищь правильно назвал это ресёрчем
К>Может быть, более практично делать проверки в рантайме, написав простенький конечный автомат. К>Вот придумать на DSL для определения такого автомата — это было бы прикольно.
Здравствуйте, remark, Вы писали:
R>2. Форсируется использование библиотеки в виде некого заранее известного, корректного и локального паттерна кода. Например так: R>
R>Понятно, что можно и корректно использовать библиотеку, если разнести вызовы по разным функциям и перемешать их в хаотическом порядке. Но зачем? Если можно записать их в одной функции и в известном порядке. Т.о. если открыть файл, который видишь первый раз, человека, код которого ни разу не видел, всё равно будешь знать что ожидать.
Если это паттерн, то почему бы его не сделать простой функцией библиотеки и не парить мозги компилятору?
Конечно, впечатляет. Но с IROV я соглашусь — в реальных проектах за такое руки отрывать надо
Здравствуйте, remark, Вы писали:
ХД>>Если это паттерн, то почему бы его не сделать простой функцией библиотеки и не парить мозги компилятору? R>Встречный вопрос: почему всё win api не сделали одной большой функцией, принимающей много-много параметров?