Есть ли ситуации, когда вы не хотели бы включать охранников? - PullRequest
7 голосов
/ 04 марта 2011

Я знаю, почему существуют встроенные средства защиты, и что #pragma once не является стандартным и поэтому не поддерживается всеми компиляторами и т. Д.

У меня другой вопрос:

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

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

Ответы [ 6 ]

9 голосов
/ 04 марта 2011

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

Кроме этого, я не могу придумать причину.

5 голосов
/ 04 марта 2011

@ sbi уже говорил о генерации кода, поэтому позвольте мне привести пример.

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

Одним из решений является использование этого трюка с множественным включением.

// myenumeration.td
MY_ENUMERATION_META_FUNCTION(Item1)
MY_ENUMERATION_META_FUNCTION(Item2)
MY_ENUMERATION_META_FUNCTION(Item3)
MY_ENUMERATION_META_FUNCTION(Item4)
MY_ENUMERATION_META_FUNCTION(Item5)

Тогда люди просто используют это так:

#define MY_ENUMERATION_META_FUNCTION(Item_) \
  case Item_: return #Item_;

char const* print(MyEnum i)
{
  switch(i) {
    #include "myenumeration.td"
  }

  __unreachable__("print");
  return 0; // to shut up gcc
}

#undef MY_ENUMERATION_META_FUNCTION

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

3 голосов
/ 04 марта 2011
<cassert>
<assert.h>

"Макрос assert переопределяется в соответствии с текущим состоянием NDEBUG каждый раз, когдавключен. "

0 голосов
/ 04 марта 2011

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

Подумайте об этом, что произойдет, если компилятор сделает ошибку и не сможет включить файл, который должен был включить? Что произойдет, если он дважды включает файл, которого не должно быть? Как бы вы это исправить?

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

Edit: Проверьте эту тему на comp.std.c ++ "#pragma один раз в стандарте ISO?"

http://groups.google.com/group/comp.std.c++/browse_thread/thread/c527240043c8df92

0 голосов
/ 04 марта 2011

Предположим, у вас есть сторонняя библиотека, и вы не можете изменить ее код. Теперь предположим, что включение файлов из этой библиотеки генерирует предупреждения компилятора. Обычно вы хотели бы скомпилировать свой собственный код с высокими уровнями предупреждений, но при этом генерируется большой набор предупреждений от использования библиотеки. Вы можете написать предупреждающие заголовки disabler / enabler, которые затем можно обернуть вокруг сторонней библиотеки, и их можно будет включать несколько раз.

Другим более сложным видом использования является итерационная конструкция препроцессора Boost: http://www.boost.org/doc/libs/1_46_0/libs/preprocessor/doc/index.html

0 голосов
/ 04 марта 2011

Это может быть проблемой, если у вас есть два заголовка в проекте, которые используют один и тот же include guard, например если у вас есть две сторонние библиотеки, и у них обеих есть заголовок, который использует защитный символ включения, такой как __CONSTANTS_H__, то вы не сможете успешно #include оба заголовка в данном модуле компиляции. Лучшее решение - #pragma once, но некоторые старые компиляторы не поддерживают это.

...