Я имею очень простой класс, называю его Основным, используемым почти во всех других файлах в большем проекте. В некоторых случаях должен быть вывод отладки, но в режиме выпуска, это не должно быть включено и быть NOOP.
В настоящее время в заголовке существует определение, который включает макрос или прочь, в зависимости от установки. Таким образом, это - определенно NOOP при выключении. Я задаюсь вопросом, если у меня есть следующий код, если компилятор (MSVS / gcc) может оптимизировать вызов функции, так, чтобы это был снова NOOP. (Путем выполнения этого переключатель мог быть в .cpp, и переключение будет намного быстрее, компилировать/связывать мудрое время).
--Header--
void printDebug(const Basic* p);
class Basic {
Basic() {
simpleSetupCode;
// this should be a NOOP in release,
// but constructor could be inlined
printDebug(this);
}
};
--Source--
// PRINT_DEBUG defined somewhere else or here
#if PRINT_DEBUG
void printDebug(const Basic* p) {
// Lengthy debug print
}
#else
void printDebug(const Basic* p) {}
#endif
Как и на все подобные вопросы, ответ таков: если это действительно важно для вас, попробуйте подход и изучите выпущенный язык ассемблера.
В настоящее время большая часть оптимизаций выполняется во время компиляции. Некоторые компиляторы, такие как LLVM , могут выполнять оптимизацию во время компоновки. Это действительно интересная идея. Предлагаю вам взглянуть.
Ожидая такой оптимизации, вы можете сделать следующее. Определите макрос, который позволит вам включить следующий оператор в зависимости от того, определена ли DEBUG или нет.
#ifdef DEBUG
#define IF_DEBUG (false) {} else
#else
#define IF_DEBUG
#endif
Вы можете использовать его так
Basic() {
simpleSetupCode;
// this should be a NOOP in release,
// but constructor could be inlined
IF_DEBUG printDebug(this);
}
, который уже намного удобнее, чем
Basic() {
simpleSetupCode;
// this should be a NOOP in release,
// but constructor could be inlined
#if DEBUG
printDebug(this);
#endif
}
Обратите внимание, что вы можете использовать его, как если бы это было ключевое слово
IF_DEBUG {
printDebug(this);
printDebug(thas);
}
#if PRINT_DEBUG
#define printDebug _real_print_debug
#else
#define printDebug(...)
#endif
Таким образом, препроцессор удалит весь отладочный код еще до того, как он попадет в компилятор.
Компилятор, возможно, может оптимизировать этот код, если он знает реализацию функции printDebug во время компиляции. Если printDebug находится в другом объектном модуле, это, возможно, может быть оптимизировано только компоновщиком, используя оптимизацию всей программы. Но единственный способ проверить это - прочитать код сборки, созданный компилятором. Если у вас уже есть макрос PRINT_DEBUG, вы можете расширить его, как определено TRACE:
#define PRINT_DEBUG // optional #ifdef PRINT_DEBUG #define PRINT_DEBUG_CALL(p) printDebug(p) #else #define PRINT_DEBUG_CALL(p) #endif void printDebug(const Basic* p); class Basic { Basic() { simpleSetupCode; // this should be a NOOP in release, // but constructor could be inlined PRINT_DEBUG_CALL(this); } }; --Source-- // PRINT_DEBUG defined somewhere else or here #if PRINT_DEBUG void printDebug(const Basic* p) { // Lengthy debug print } #endif
эээ, почему бы не использовать макрос препроцессора по-другому?
Просто в голове, что-то вроде:
#define DEBUG_TRACE(p)
#ifdef PRINT_DEBUG
printDebug(p);
#else
;
#endif