Почему используются безымянные пространства имен и каковы их преимущества?
Я только что присоединился к новому программному проекту C++, и я пытаюсь понять дизайн. Проект часто использует безымянные пространства имен. Например, что-то подобное может произойти в файле определения класса:
// newusertype.cc
namespace {
const int SIZE_OF_ARRAY_X;
const int SIZE_OF_ARRAY_Y;
bool getState(userType*,otherUserType*);
}
newusertype::newusertype(...) {...
каковы конструктивные соображения, которые могут привести к использованию безымянного пространства имен? Каковы преимущества и недостатки?
6 ответов:
(в последующем
зачеркнутавещи-это вещи, которые больше не применяются к C++11, но применяются к C++03. C++11 больше почти не имеет различий (если они есть, это просто различия в языке, которые я не могу вспомнить).).безымянные пространства имен-это утилита для создания идентификатора
эффективноединица перевода местной. Они ведут себя так, как если бы вы выбрали уникальное имя за единицу перевода пространство имен:namespace unique { /* empty */ } using namespace unique; namespace unique { /* namespace body. stuff in here */ }дополнительный шаг с использованием пустого тела важен, поэтому вы уже можете ссылаться в теле пространства имен на идентификаторы, такие как
::nameкоторые определены в этом пространстве имен, так как директива using уже имела место.это означает, что вы можете иметь свободные функции под названием (например)
helpчто может существовать в нескольких единицах трансляции, и они не будут конфликтовать во время ссылки,так как все они получили уникальное имя из-за их уникального пространства имен они находятся в. Эффект практически идентичен использованиюstaticключевое слово, используемое в C, которое вы можете поместить в объявление идентификаторов.безымянные пространства имен являются превосходной альтернативой, способной даже сделать единицу перевода типа локальной.staticиспользуется таким образом является устаревшим в C++, так какnamespace { int a1; } static int a2;и
a' s являются локальными единицами перевода и не будут конфликтовать во время ссылки. Но разница в том, чтоa1в анонимном пространстве именпростополучает уникальное имя.он все еще имеет внешнюю связь и может быть экспортирован в таблицу символов создаваемого объектного файла. Это становится важным, если вы хотите использовать свой адрес в качестве аргумента шаблона:template<int * ptr> struct sample { }; // OK - a1 has external linkage sample<&a1> s1; // NOT OK - translation unit locality is done by giving a2 internal linkage. sample<&a2> s2;параметры шаблона должны иметь внешнюю связь, поэтому в этом случае идентификатор должен быть помещен в анонимное пространство имен.
читать прекрасную статью на Комо-вычислительной техники ' почему безымянный пространство имен используется вместо статического?.
наличие чего-то в анонимном пространстве имен означает, что это локально для этого ЕП (.cpp файл и все его включает в себя) это означает, что если другой символ с тем же именем определяется в другом месте не будет нарушения Одно Правило Определения (ODR).
это то же самое, что и способ C иметь статическую глобальную переменную или статическую функцию, но он также может использоваться для определений классов (и должен использоваться вместо
staticin С.)++все анонимные пространства имен в одном файле рассматриваются как одно и то же пространство имен, и все анонимные пространства имен в разных файлах различны. Анонимное пространство имен эквивалентно:
namespace __unique_compiler_generated_identifer0x42 { ... } using namespace __unique_compiler_generated_identifer0x42;
пример показывает, что люди в проекте, к которому вы присоединились, не понимают анонимные пространства имен:)
namespace { const int SIZE_OF_ARRAY_X; const int SIZE_OF_ARRAY_Y;они не должны быть в анонимном пространстве имен, так как
constобъект уже имеет статическую связь и поэтому не может конфликтовать с идентификаторами того же имени в другой единице перевода.bool getState(userType*,otherUserType*); }и это на самом деле пессимизм:
getState()имеет внешние связи. Обычно лучше предпочесть статическую связь, так как это не так засорять таблицу символов. Лучше написатьstatic bool getState(/*...*/);здесь. Я попал в ту же ловушку (в стандарте есть формулировка, которая предполагает, что статика файлов каким-то образом устарела в пользу анонимных пространств имен), но работая в большом проекте C++, таком как KDE, вы получаете много людей, которые снова поворачивают голову направо :)
в дополнение к другим ответам на этот вопрос, использование анонимного пространства имен также может повысить производительность. Поскольку символы в пространстве имен не нуждаются в какой-либо внешней привязке, компилятор свободнее выполняет агрессивную оптимизацию кода в пространстве имен. Например, функция, которая вызывается несколько раз в цикле может быть встроен без какого-либо влияния на размер кода.
например, на моей системе следующий код занимает около 70% времени выполнения, если используется анонимное пространство имен (x86-64 gcc-4.6.3 и-O2; обратите внимание, что дополнительный код в add_val заставляет компилятор не включать его дважды).
#include <iostream> namespace { double a; void b(double x) { a -= x; } void add_val(double x) { a += x; if(x==0.01) b(0); if(x==0.02) b(0.6); if(x==0.03) b(-0.1); if(x==0.04) b(0.4); } } int main() { a = 0; for(int i=0; i<1000000000; ++i) { add_val(i*1e-10); } std::cout << a << '\n'; return 0; }
анонимное пространство имен создает вложенные переменные, функции, классы и т. д. доступно только внутри этого файла. В вашем примере это способ избежать глобальных переменных. Нет разницы в производительности во время выполнения или компиляции.
существует не так много преимуществ или недостатков, кроме "хочу ли я эту переменную, функцию, класс и т. д. быть публичным или частным?"
Безымянное пространство имен ограничивает доступ класса, переменной, функции и объектов к файлу, в котором оно определено. Функциональность безымянного пространства имен аналогична
staticключевое слово в C/с++.staticключевое слово ограничивает доступ глобальной переменной и функции к файлу, в котором они определены.
Существует разница между безымянным пространством имен иstaticключевое слово, из-за которого Безымянное пространство имен имеет преимущество перед статическим.staticключевое слово можно использовать с переменной, функцией и объекты, но не с определяемым пользователем классом.
Например:static int x; // Correctа,
static class xyz {/*Body of class*/} //Wrong static structure {/*Body of structure*/} //Wrongно то же самое может быть возможно с безымянным пространством имен. Например,
namespace { class xyz {/*Body of class*/} static structure {/*Body of structure*/} } //Correct
Comments