На данный вопрос уже ответили:
Подскажите пожалуйста, в чём разница между двумя директивами и какую лучше использовать в коде?
Файл MyClass.h
#include <iostream>
#include <string>
#ifndef MYCLASS_H
#define MYCLASS_H
//class description
#endif
Или
#pragma once
#include <iostream>
#include <string>
//class description
Директива #pragma once
является зависимой от реализации компилятора, а потому может не поддерживаться отдельными компиляторами, и будет просто игнорироваться.
Директивы #ifndef
и #define
являются стандартными директивами, а потому их использование в данном контексте будет одинаково для всех компиляторов.
Множество компиляторов, не поддерживающих #pragma once
на сегодняшний день стремится к пустому множеству. В основном там сейчас неразвиваемые либо заброшенные.
В enWiki есть таблица со ссылками на источники. В этом списке только PGI не поддерживает #pragma once
.
Присутствующий в списке на ruWiki OracleSolarisStudio
исправил это упущение в версии 12.5
Этот плюс весьма призрачен. Ускорения компиляции от его использования вы можете не достичь, компиляторы умеют(gcc точно) оптимизировать и то, и то.
КоллизииОсновной минус include guards
- вы не можете гарантировать, что придумали уникальный идентификатор.
Если вы никогда не планируете подключать чужеродные библиотеки, можете придумать себе правило для include guards
и жить спокойно.
В ином случае, они ломают всё то, для чего в c++
существуют namespaces. Простого MYCLASS_H
явно недостаточно, ведь он может быть уже определён в другой подключаемой библиотеке, либо если вы и пишете библиотеку - в клиентском коде.
Вам придётся выдумывать действительно уникальные идентификаторы, навроде __VENDOR_PACKAGE_MYCLASS
или __MYCLASS_%TIMESTAMP%
, чтобы исключить вероятность коллизии.
Разумеется, что именно использовать в вашем проекте - решать только вам. Однако, очевидно, что нет никаких причин не использовать более лаконичную версию, кроме фанатичной "Отсутствует в стандарте
".
PS: Вы некорректно применяете include guards
- они обязательно должны охватывать весь файл целиком, иначе компилятор никак не сможет оптимизировать их, чтобы не запускать препроцессор для этого файла повторно.
Фундаментальное отличие заключается в том, что #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
, то в подавляющем большинстве случаев они должны покрывать весь файл от начала до конца.
Виртуальный выделенный сервер (VDS) становится отличным выбором
Имеется vector<vector<char>> и файл с текстомЦель: ввод этого текста в двумерный вектор
Задача - создать класс Группа, содержащий массив объектов класса Студент, и добавить в него меню для работы с группойЯ решил реализовать меню...