Допустимое использование для C ++ включает охрану, кроме, ну, в том числе, include-guarding? - PullRequest
0 голосов
/ 02 февраля 2011

Этот вопрос является одним из нескольких, в которых обсуждаются соглашения об именах для C ++, включающие охранники. Человек, задающий этот вопрос, считает, что это соглашение об именах:

#ifndef FOO_H
#define FOO_H

// ...

#endif

немного неинтуитивен, когда взят сам по себе (что означает FOO_H?), И я склонен согласиться.

Другие говорят, что, исключая необходимость добавлять больше материала для лучшего предотвращения столкновений (например, PROJECTNAME_FOO_H_SDFFGH69876GF), имя FOO_H просто прекрасно, потому что из его контекста ясно, какова его цель (а именно, в начале из файлов с таким же именем, и ясно, что это включаемый охранник).

Я мог бы купить это, если единственная цель наличия FOO_H состояла бы в защите от многократного включения, но есть ли условия, для которых я хотел бы иметь FOO_H в других местах файлов? Я думаю, что условная компиляция была бы хорошей причиной, и в этом случае было бы более понятным присвоить ей имя типа FOO_H_INCLUDED.

Существует ли прямолинейное использование, подобное этому, или мне следует избегать перепрофилирования включаемых охранников?

Ответы [ 5 ]

4 голосов
/ 02 февраля 2011

Я думаю, что вопрос ошибочен сам по себе.Термин «включить охрану» относится к #define с и проверяет #defined в конкретном использовании для защиты от многократного включения , что также говорит о том, что это единственное использование для этого.

Теперь, если немного более обобщенно, определения и условная компиляция могут использоваться для других целей, таких как написание фрагментов кода, которые зависят от платформы и будут скомпилированы только при некоторых обстоятельствах ...

Будь FOO_Hили FOO_H_INCLUDED лучше, я всегда буду говорить, что последний является наиболее выразительным, и затем я вернусь к vi и наберу FOO_H в моем следующем заголовке foo.h.Опять же, как я уже упоминал в комментарии к другому вопросу, вы привыкли к шаблону:

#ifndef XXXXXXXXX
#define XXXXXXXXX

#endif

в качестве первых двух и последней строки в файле, и вы заканчиваете замечать.До тех пор, пока вы не воспользуетесь тем же именем ...

1 голос
/ 02 февраля 2011

Для перепрофилирования: если все содержимое файла не окружено ifndef / define / endif, тогда FOO_H на самом деле не файл включает в себя guard, он только защищает часть файла. Так что, возможно, он не должен быть назван в честь всего файла. Рекурсивное включение одного и того же файла - одна из ситуаций, когда это может произойти.

Тем не менее, я подозреваю, что даже в этом случае должно быть довольно очевидно, для чего предназначено определение (во всяком случае, более очевидно, что любая хитрая вещь, которую вы делаете, не просто включает охрану). Везде, где вы видите шаблон ifndef FOO / определение FOO или даже просто ifndef FOO / определение большого количества вещей, простой комментарий может сделать значение FOO очевидным, если его еще нет.

Если какая-то часть вопроса заключается в том, может ли токен FOO_H когда-либо использоваться для какой-либо другой цели: я предполагаю, что если у вас есть файл с именем uppercase.h, который использует UPPERCASE_H в качестве защитного ключа, тогда это может возможно столкновение с чьим-либо rot13.h, содержащим #define UPPERCASE_A ('N') и т. д. Глупый пример, но если вы определяете свойства букв в заголовочном файле, то не смешно думать, что некоторые из них могут заканчиваться _H.

Более реалистично, у меня были проекты с включаемыми файлами с одинаковым базовым именем в разных каталогах.

Так что, независимо от контекста и перепрофилирования, я бы не стал использовать FOO_H в качестве включающего охранника.

1 голос
/ 02 февраля 2011

Я думаю, что условная компиляция была бы хорошей причиной, и в этом случае было бы более понятным назвать ее как FOO_H_INCLUDED.

Я вижу только одно очень узкое использование, чтобы избежать включениязаголовок, когда вам нужно только предварительное объявление, но вы хотите пропустить предварительные объявления, если заголовок был ранее включен.

Однако, это не является узким местом в компиляции C ++ сегодня, и добавленная путаница в любом из них всегдаиметь предварительные декларации или всегда включать заголовок не имеет смысла.

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

1 голос
/ 02 февраля 2011

На мой взгляд, включать охранников следует включать охранников и ничего более. Если вы хотите условную компиляцию, я бы определил что-то еще. Если бы вы добавили в свой код #if defined(FOO_H), я думаю, что люди сочтут это странным, поскольку _H обычно указывает на включение охранника.

Одна вещь, о которой я могу подумать, это проверка того, был ли файл уже включен (дух!), Чтобы вам не пришлось включать файл самостоятельно. Я не уверен, ускорит ли это компиляцию или нет, по сравнению с предварительными декларациями или #pragma once

В main.cpp:

#include "bar.h" // comment this line to see the difference
#include "foo.h"

int main()
{
    return 0;
}

В бар.ч:

#ifndef BAR_H
#define BAR_H

class BarClass
{
};

#endif

В foo.h:

#ifndef FOO_H
#define FOO_H

#if !defined(BAR_H)
#error bar h was not included // forgot how to do compiler warnings...
#include "bar.h" // we should include the file
#else
#error bar h was included // same thing, should be changed to warning
#endif

// do something with BarClass

#endif FOO_H
1 голос
/ 02 февраля 2011

Иногда я использую это для заголовочных файлов "реализации". Фактическая схема присвоения имен охранникам может отличаться.

#ifndef FOO_IMPL_H
#define FOO_IMPL_H

#ifndef FOO_H
#error Don't include this directly
#endif

// Ugly implementation of the stuff in foo.h, with an uncountable
// number of template and typename keywords

#endif 
...