Для чего нужна команда pragma once?

Здравствуйте. Очень часто встречаю конструкцию #pragma once в чужих исходниках. Скажите, для чего она нужна?

Илья, директива препроцессора #pragma once применяется для защиты от «двойного подключения» заголовочных файлов.

Например, у нас есть 3 файла — main.cpp, header.h и something.cpp.

header.h

class Foo {
    public:
        void method();
    private:
        int member;
};

something.cpp

#include "header.h"

void Foo::method()
{
    member = 1 + 1;
}

main.cpp

#include <iostream>
#include "header.h"

int main()
{
    Foo *obj = new Foo;
    obj->method();
    return 0;
}

Файл header.h подключается одновременно в main.cpp и something.cpp. Из за этого объявление класса Foo будет выполнено более одного раза, и мы получим ошибку при компиляции.

Для того, чтобы избежать подобных проблем, используется директива #pragma once, которая указывает препроцессору, что файл подключается только один раз.

#pragma once

class Foo {
    public:
        void method();
    private:
        int member;
};

Еще один вариант — include guard, который в отличии от #pragma once, умеет корректно работать с символическими ссылками.

На счёт #pragma once — всё правильно. Более того, Микрософт пишет, что эта прагма сокращает время компиляции, поскольку файлы обрабатываются только один раз. Сильно подозреваю, что в этом случае для компиляции требуется больше оперативной памяти — бесплатный сыр, как известно...

А вот твой пример не совсем корректный.

В данном случае будет профит только от сокращения времени компиляции. Двойного определения класса Foo здесь не будет в любом случае.

Файлы main.cpp и something.cpp являются отдельными единицами компиляции и встретятся только на этапе сборки, поэтому header.h будет включаться в них независимо друг от друга.

Для двойного включения нужна немного другая конструкция:

header1.h

#include <iostream>

void bar(std::ostream & os, int arg);

main1.cpp

#include <iostream>
#include "header1.h"

int main() {
// ...
bar(std::cout, 10);
}

Вот в этом случае заголовочный файл <iostream> должен быть защищён от двойного включения, поскольку при обработке файла main1.cpp сначала он включается явно директивой #include, а затем неявно при включении заголовочного файла header1.h.

Причём файл something1.cpp, содержащий реализацию функции bar(), мы здесь не рассматриваем, поскольку это опять-таки отдельная единица компиляции.

Замечание для начинающих. При компиляции каждый файл .cpp сначала обрабатывается препроцессором. Препроцессор — штука по своей логике достаточно примитивная: читает текст программы из входного файла, обрабатывает директивы препроцессора (#include, #define, #if/#elif/#else/#endif и пр., но не #pragma(!) — это не директива препроцессора) и макросы и пишет получившийся текст программы во временный файл, откуда его потом подхватывает компилятор. Найдя директиву #include, препроцессор тупо заменяет её на содержимое указанного в директиве файла и продолжает обрабатывать получившийся текст.

Файлы main.cpp и something.cpp являются отдельными единицами компиляции и встретятся только на этапе сборки, поэтому header.h будет включаться в них независимо друг от друга.

Да, точно. Спасибо :)

Внимание! Это довольно старый топик, посты в него не попадут в новые, и их никто не увидит. Пишите пост, если хотите просто дополнить топик, а чтобы задать новый вопрос — начните новый.

Ответить

Вы можете использовать разметку markdown для оформления комментариев и постов. Используйте функцию предпросмотра для проверки корректности разметки.

Пожалуйста, оформляйте исходный код в соответствии с правилами разметки. Для того, чтобы вставить код в комментарий, скопируйте его в текстовое поле ниже, после чего выделите то, что скопировали и нажмите кнопку «код» в панели инструментов. Иначе ваш код может принять нечитаемый вид.

Либо производите оформление кода вручную, следующим образом:

``` #include <iostream> using namespace std; int main() { // ... } ```

Предпросмотр сообщения

Ваше сообщение пусто.