Защита от множественного подключения заголовочного файла (1 ответ) Закрыт 7 лет назад.
Подскажите пожалуйста, в чём разница между двумя директивами и какую лучше использовать в коде? Файл MyClass.h #include #include #ifndef MYCLASS_H #define MYCLASS_H //class description #endif Или #pragma once #include #include //class description
Ответ Фундаментальное отличие заключается в том, что #pragma once относится ко всему заголовочному файлу целиком. Изначальной идеей #pragma once было то, что в процессе обработки отдельной единицы трансляции компилятор (препроцессор) имеет право даже и не искать и не открывать второй раз заголовочные файлы, которые содержат #pragma once. Именно в этой форме когда-то и предлагалось стандартизовать #pragma once - как средство ускорения компиляции. Include guards #ifdef/#endif, понятное дело, имеют право покрывать не весь заголовочный файл, т.е. эта пара в общем случае не относится ко всему файлу целиком. Это означает, что в общем случае компилятор будет вынужден найти и открыть заголовочный файл, чтобы включить участки, не попавшие внутрь #ifdef/#endif. В то же время понятно, что компилятору не составляет никакого труда проанализировать содержимое заголовочного файла при первом прочтении и распознать явное идиоматическое использование #ifdef/#endif, прокрывающее весь файл целиком от начала до конца. В такой ситуации #pragma once не предоставляет никакой практической выгоды по сравнению с #ifdef/#endif. Именно по этой причине от стандартизации #pragma once в свое время отказались - как от фичи, не привносящей никакой дополнительной ценности (кроме, разве что, компактной записи и того, что, как заметили @vp_arth и @VladD, нет необходимости выдумывать уникальный идентификатор). Соответственно, ответ очевиден - пользуйтесь стандартной функциональностью #ifdef/#endif и забудьте про нестандартный #pragma once. Может быть в каком-то случае вы заметите, что компилятор (препроцессор) не хочет оптимизировать обработку на основе анализа #ifdef/#endif и использование #pragma once действительно ускоряет компиляцию... Тогда, если для вас это критично - может быть стоит добавить в ваши файлы #pragma once. Еще одно соображение против стандартизации #pragma once заключалось в том, что для обеспечения жесткой гарантии ее спецификации (т.е. строго единственного включения), необходимо иметь возможность надежно определять идентичность файла по указанному в директиве #include пути. Это задача в общем случае исключительно трудноразрешима во многих существующих файловых системах. Поэтому будьте осторожны с наивными пионерскими заявлениями типа "все современные компиляторы поддерживают #pragma once". Ни о какой поддержке строгой спецификации ни в одном компиляторе речи не идет. И, разумеется, ни о каких гарантиях одинаковости поведения между компиляторами речи не идет тоже. По этой причине, если вы таки соберетесь использовать #pragma once в своем коде, используйте ее вместе с include guards, а не вместо их. P.S. Включение других заголовочных файлов обычно "кладут" внутрь вашего #ifdef/#endif. Им нет никакой причины находиться снаружи. Манерой оставлять их снаружи вы, возможно, рискуете подавить вышеупомянутую оптимизацию. Если уж вы пользуетесь #ifdef/#endif, то в подавляющем большинстве случаев они должны покрывать весь файл от начала до конца.