Особенностью C ++ является возможность создавать безымянные (анонимные) пространства имен, например:
namespace {
int cannotAccessOutsideThisFile() { ... }
} // namespace
Можно подумать, что такая функция будет бесполезной - поскольку вы не можете указать имя пространства имен, невозможно получить к нему доступ извне. Но эти безымянные пространства имен являются доступными в файле они создали в, как если бы вы имели неявное с помощью придаточного к ним.
Мой вопрос: почему или когда это было бы предпочтительнее использования статических функций? Или это по сути два способа сделать одно и то же?
c++
namespaces
Главный Компьютерщик
источник
источник
static
в этом контексте было устаревшим ; хотя безымянное пространство имен является превосходной альтернативойstatic
, есть случаи, когда оно выходит из строя, когдаstatic
приходит на помощь .Ответы:
Стандарт C ++ гласит в разделе 7.3.1.1 Безымянные пространства имен, параграф 2:Статика применяется только к именам объектов, функций и анонимных объединений, но не к объявлениям типов.
Редактировать:
Решение об отказе от использования этого ключевого слова static (влияет на видимость объявления переменной в модуле перевода) было отменено ( ссылка ). В этом случае использование статического или безымянного пространства имен вернулось к тому, чтобы быть по сути двумя способами сделать одно и то же. Для дальнейшего обсуждения, пожалуйста, смотрите этот вопрос.
Неназванные пространства имен по-прежнему имеют то преимущество, что позволяют вам определять типы локальных блоков перевода. Пожалуйста, смотрите этот вопрос для получения более подробной информации.
Кредит идет Майку Перси за то, что он обратил на это мое внимание.
источник
namespace
s неявно имеют внутреннюю связь, поэтому не должно быть никакой разницы. Любые проблемы, которые ранее могли возникнуть из-за неправильной формулировки, были решены путем введения этого требования в C ++ 11.Помещение методов в анонимное пространство имен предотвращает случайное нарушение правила One Definition , позволяя вам никогда не беспокоиться о присвоении имен вашим вспомогательным методам так же, как и другим методам, на которые вы можете ссылаться.
И, как указал luke, анонимные пространства имен предпочитаются стандартом над статическими членами.
источник
Есть один крайний случай, когда static имеет удивительный эффект (по крайней мере, для меня). Стандарт C ++ 03 в 14.6.4.2/1 гласит:
Код ниже будет звонить,
foo(void*)
а не так,foo(S const &)
как вы могли ожидать.Само по себе это, вероятно, не так уж и сложно, но подчеркивает, что для полностью совместимого компилятора C ++ (то есть с поддержкой
export
)static
ключевое слово по-прежнему будет иметь функциональность, недоступную другим способом.Единственный способ гарантировать, что функция в нашем безымянном пространстве имен не будет найдена в шаблонах, использующих ADL, - это сделать это
static
.Обновление для Modern C ++
Начиная с C ++ '11, члены безымянного пространства имен неявно имеют внутреннюю связь (3.5 / 4):
Но в то же время 14.6.4.2/1 был обновлен, чтобы убрать упоминание о связи (это взято из C ++ '14):
В результате этого конкретного различия между статическими и неназванными членами пространства имен больше не существует.
источник
NS::S
работы, неS
нужно не быть внутриnamespace {}
?Недавно я начал заменять статические ключевые слова анонимными пространствами имен в моем коде, но сразу столкнулся с проблемой, когда переменные в пространстве имен больше не были доступны для проверки в моем отладчике. Я использовал VC60, поэтому я не знаю, не является ли это проблемой с другими отладчиками. Мой обходной путь состоял в том, чтобы определить пространство имен 'module', где я дал ему имя моего файла cpp.
Например, в моем файле XmlUtil.cpp я определяю пространство имен
XmlUtil_I { ... }
для всех переменных и функций моего модуля. Таким образом, я могу применитьXmlUtil_I::
квалификацию в отладчике для доступа к переменным. В этом случае_I
он отличается от публичного пространства имен, такого,XmlUtil
которое я, возможно, захочу использовать в другом месте.Я предполагаю, что потенциальный недостаток этого подхода по сравнению с действительно анонимным состоит в том, что кто-то может нарушить желаемую статическую область, используя квалификатор пространства имен в других модулях. Я не знаю, является ли это серьезной проблемой, хотя.
источник
#if DEBUG namespace BlahBlah_private { #else namespace { #endif
, так что «пространство имен модуля» присутствует только в отладочных сборках, а истинное анонимное пространство имен используется в противном случае. Было бы хорошо, если бы отладчики дали хороший способ справиться с этим. Doxygen смущается этим также.Использование статического ключевого слова для этой цели не рекомендуется стандартом C ++ 98. Проблема со статическим в том, что он не относится к определению типа. Это также перегруженное ключевое слово, используемое по-разному в разных контекстах, поэтому безымянные пространства имен немного упрощают вещи.
источник
Из опыта я просто отмечу, что, хотя это способ C ++ поместить ранее статические функции в анонимное пространство имен, старые компиляторы могут иногда иметь проблемы с этим. В настоящее время я работаю с несколькими компиляторами для наших целевых платформ, и более современный компилятор Linux хорошо размещает функции в анонимном пространстве имен.
Но более старый компилятор, работающий на Solaris, который мы используем до неуказанного будущего выпуска, иногда принимает его, а иногда отмечает его как ошибку. Ошибка не в том, что меня беспокоит, а в том, что он может делать, когда принимает это. Поэтому, пока мы не станем современными по всем направлениям, мы все еще будем использовать статические (обычно классовые) функции, где мы предпочитаем анонимное пространство имен.
источник
Кроме того, если кто-то использует статическое ключевое слово для переменной, как в этом примере:
Это не будет видно в файле сопоставления
источник
Отличие компилятора между анонимными пространствами имен и статическими функциями можно увидеть при компиляции следующего кода.
Компиляция этого кода с VS 2017 (указание флага предупреждения уровня 4 / W4 для включения предупреждения C4505: удаленная локальная функция была удалена ) и gcc 4.9 с флагом -Wunused-function или -Wall показывает, что VS 2017 будет выдавать предупреждение только для неиспользуемая статическая функция. gcc 4.9 и выше, а также clang 3.3 и выше, будут выдавать предупреждения для функции без ссылок в пространстве имен, а также предупреждение о неиспользуемой статической функции.
Живая демоверсия gcc 4.9 и MSVC 2017
источник
Лично я предпочитаю статические функции над безымянными пространствами имен по следующим причинам:
Из определения функции ясно и ясно, что она является частной по отношению к модулю перевода, где она компилируется. С безымянным пространством имен вам может понадобиться прокрутить и выполнить поиск, чтобы увидеть, находится ли функция в пространстве имен.
Некоторые (более старые) компиляторы могут рассматривать функции в пространствах имен как внешние. В VS2017 они все еще внешние. По этой причине, даже если функция находится в безымянном пространстве имен, вы все равно можете пометить их как статические.
Статические функции ведут себя очень похоже в C или C ++, тогда как безымянные пространства имен, очевидно, являются только C ++. безымянные пространства имен также добавляют дополнительный уровень отступа, и мне это не нравится :)
Итак, я рад видеть, что использование static для функций больше не считается устаревшим .
источник
static
ключевое слово фактически применяет локальную связь с функцией. Кроме того, конечно, только бредовый сумасшедший фактически добавит отступ для пространств имен?Узнав об этой функции только сейчас, читая ваш вопрос, я могу только строить догадки. Похоже, это обеспечивает несколько преимуществ по сравнению со статической переменной на уровне файлов:
Мне было бы интересно узнать, использовал ли кто-нибудь анонимные пространства имен в реальном коде.
источник
Разница заключается в названии искаженного идентификатора (
_ZN12_GLOBAL__N_11bE
vs_ZL1b
, что на самом деле не имеет значения, но оба они собраны в локальные символы в таблице символов (отсутствие.global
директивы asm).Что касается вложенного анонимного пространства имен:
Все анонимные пространства имен 1-го уровня в модуле перевода объединены друг с другом, все вложенные анонимные пространства имен 2-го уровня в модуле перевода объединены друг с другом
Вы также можете иметь вложенное (встроенное) пространство имен в анонимном пространстве имен
Вы также можете иметь анонимные встроенные пространства имен, но, насколько я могу судить,
inline
на анонимное пространство имен влияет 0_ZL1b
:_Z
означает, что это искаженный идентификатор.L
означает, что это локальный символstatic
.1
длина идентификатора,b
а затем идентификаторb
_ZN12_GLOBAL__N_11aE
_Z
означает, что это искаженный идентификатор.N
означает, что это пространство имен12
- это длина имени анонимного пространства имен_GLOBAL__N_1
, затем имя анонимного пространства имен_GLOBAL__N_1
, затем1
длина идентификатораa
,a
это идентификаторa
иE
закрытие идентификатора, который находится в пространстве имен._ZN12_GLOBAL__N_11A1aE
такой же, как указано выше, за исключением того, что есть еще один уровень пространства имен в нем1A
источник