Является ли хорошей практикой использование #ifdef во время разработки для переключения между различными типами поведения? Например, я хочу изменить поведение существующего кода, у меня есть несколько идей, как изменить поведение, и необходимо переключаться между различными реализациями, чтобы тестировать и сравнивать разные подходы. Обычно изменения в коде сложны и влияют на разные методы в разных файлах.
Я обычно вводю несколько идентификаторов и делаю что-то подобное
void foo()
{
doSomething1();
#ifdef APPROACH1
foo_approach1();
#endif
doSomething2();
#ifdef APPROACH2
foo_approach2();
#endif
}
void bar()
{
doSomething3();
#ifndef APPROACH3
doSomething4();
#endif
doSomething5();
#ifdef APPROACH2
bar_approach2();
#endif
}
int main()
{
foo();
bar();
return 0;
}
Это позволяет быстро переключаться между различными подходами и делать все только в одной копии исходного кода. Это хороший подход для развития или есть лучшая практика?
c++
programming-practices
development-process
Юрий Шклярик
источник
источник
#ifdef
блоках, если блок выключен. Мы столкнулись со случаями, когда код может легко устареть и не скомпилироваться, если вы обычно не строите все пути.#ifdefs
менее громоздким.Ответы:
Я бы предпочел использовать ветки контроля версий для этого варианта использования. Это позволяет вам проводить различия между реализациями, вести отдельную историю для каждой из них, и когда вы приняли решение и хотите удалить одну из версий, вы просто отбрасываете эту ветку вместо того, чтобы выполнять подверженное ошибкам редактирование.
источник
git
особенно искусен в подобных вещах. Может быть, не так многоsvn
,hg
или другие, но это еще можно сделать.git branch
!Когда вы держите молоток, все выглядит как гвоздь. Это заманчиво, когда вы знаете, как
#ifdef
работает его использование в качестве своего рода средства для получения пользовательского поведения в вашей программе. Я знаю, потому что я сделал ту же ошибку.Я унаследовал унаследованную программу, написанную на MFC C ++, которая уже использовалась
#ifdef
для определения значений, специфичных для платформы. Это означало, что я мог скомпилировать свою программу для использования на 32-битной или 64-битной платформе, просто определяя (или в некоторых случаях не определяя) конкретные значения макросов.Тогда возникла проблема, что мне нужно было написать пользовательское поведение для клиента. Я мог бы создать ветку и создать отдельную базу кода для клиента, но это сделало бы адское обслуживание. Я мог бы также определить значения конфигурации, которые будут считываться программой при запуске, и использовать эти значения для определения поведения, но затем мне пришлось бы создавать собственные настройки, чтобы добавить правильные значения конфигурации в файлы конфигурации для каждого клиента.
Я испытал искушение и сдался. Я написал
#ifdef
разделы в своем коде, чтобы различать различные варианты поведения. Не заблуждайтесь, сначала это не было чем-то сверх Внесены очень незначительные изменения в поведение, что позволило мне распространять версии программы среди наших клиентов, и мне не нужно иметь более одной версии базы кода.Со временем это все равно стало адским обслуживанием, потому что программа больше не велась единообразно. Если я хотел протестировать версию программы, я должен был обязательно знать, кто был клиентом. Код, хотя я и пытался сократить его до одного или двух заголовочных файлов, был очень загроможден, и благодаря подходу быстрого исправления
#ifdef
такие решения распространялись по всей программе, как злокачественный рак.С тех пор я усвоил урок, и вы тоже должны. Используйте его, если вам абсолютно необходимо, и используйте его строго для изменений платформы. Лучший способ приблизиться к различиям в поведении между программами (и, следовательно, клиентами) - это изменить только конфигурацию, загруженную при запуске. Программа остается последовательной, и ее становится легче читать и отлаживать.
источник
Временно нет ничего плохого в том, что вы делаете (скажем, перед регистрацией): это отличный способ протестировать различные комбинации техник или игнорировать часть кода (хотя это говорит о проблемах само по себе).
Но предупреждаю: не держите ветки #ifdef, это немного более расстраивает, чем тратит мое время на чтение одной и той же вещи, реализованной четырьмя различными способами, только чтобы выяснить, какой из них я должен читать .
Чтение #ifdef требует усилий, так как вы должны помнить, чтобы пропустить его! Не усложняй, чем должен быть.
Используйте #ifdefs как можно реже. Как правило, есть способы сделать это в среде разработки для постоянных различий, таких как сборки Debug / Release или для разных архитектур.
Я написал функции библиотеки, которые зависели от включенных версий библиотеки, которые требовали разбиения #ifdef. Так что иногда это может быть единственным или самым простым способом, но даже тогда вы должны расстраиваться из-за их сохранения.
источник
Такое использование #ifdefs делает код очень сложным для чтения.
Так что нет, не используйте #ifdefs таким образом.
Может быть множество аргументов, почему бы не использовать ifdefs, для меня этого достаточно.
Может сделать много вещей, которые он может сделать:
Все в зависимости от того, какие подходы определены или нет. Что это делает, совершенно неясно на первый взгляд.
источник