Почему используются безымянные пространства имен и каковы их преимущества? - PullRequest
206 голосов
/ 10 декабря 2008

Я только что присоединился к новому программному проекту на C ++ и пытаюсь понять дизайн. В проекте часто используются безымянные пространства имен. Например, что-то подобное может произойти в файле определения класса:

// newusertype.cc
namespace {
  const int SIZE_OF_ARRAY_X;
  const int SIZE_OF_ARRAY_Y;
  bool getState(userType*,otherUserType*);
}

newusertype::newusertype(...) {...

Какие конструктивные соображения могут привести к использованию безымянного пространства имен? Каковы преимущества и недостатки?

Ответы [ 6 ]

170 голосов
/ 10 декабря 2008

(Далее вещи - это вещи, которые больше не применяются к C ++ 11, но применимы к C ++ 03. C ++ 11 больше не делает почти никаких различий (если они есть, то это просто язык Различия адвоката, которые я не могу вспомнить).).

Безымянные пространства имен - это утилита, позволяющая сделать единицу перевода идентификатора локальной. Они ведут себя так, как если бы вы выбрали уникальное имя для каждой единицы перевода для пространства имен:

namespace unique { /* empty */ }
using namespace unique;
namespace unique { /* namespace body. stuff in here */ }

Дополнительный шаг с использованием пустого тела важен, поэтому вы уже можете ссылаться в теле пространства имен на идентификаторы, подобные ::name, которые определены в этом пространстве имен, поскольку директива using уже имела место.

Это означает, что вы можете иметь бесплатные функции (например) help, которые могут существовать в нескольких единицах перевода, и они не будут конфликтовать во время соединения. Эффект почти идентичен использованию ключевого слова static, используемого в C, которое вы можете вставить в объявление идентификаторов. Неназванные пространства имен - превосходная альтернатива, позволяющая даже сделать единицу перевода типа локальной.

namespace { int a1; }
static int a2;

Оба a являются локальными единицами перевода и не будут конфликтовать во время ссылки. Но разница в том, что a1 в анонимном пространстве имен получает уникальное имя.

Прочитайте отличную статью на comeau-computing Почему вместо статического используется безымянное пространство имен? ( Зеркало Archive.org ).

59 голосов
/ 10 декабря 2008

Наличие чего-либо в анонимном пространстве имен означает, что оно локально для этой единицы перевода (файл .cpp и все его включения), это означает, что если в другом месте определен другой символ с таким же именем, нарушения не будет правила One Definition (ODR).

Это то же самое, что и способ C иметь статическую глобальную переменную или статическую функцию, но он также может использоваться для определений классов (и должен использоваться вместо static в C ++).

Все анонимные пространства имен в одном и том же файле рассматриваются как одно и то же пространство имен, и все анонимные пространства имен в разных файлах различны. Анонимное пространство имен эквивалентно:

namespace __unique_compiler_generated_identifer0x42 {
    ...
}
using namespace __unique_compiler_generated_identifer0x42;
12 голосов
/ 29 августа 2014

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

Например, в моей системе следующий код занимает около 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;
}
12 голосов
/ 24 июля 2009

Пример показывает, что люди в проекте, к которому вы присоединились, не понимают анонимных пространств имен:)

namespace {
    const int SIZE_OF_ARRAY_X;
    const int SIZE_OF_ARRAY_Y;

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

    bool getState(userType*,otherUserType*);
}

И это на самом деле пессимизация: getState() имеет внешнюю связь. Обычно лучше использовать статическую связь, так как это не загрязняет таблицу символов. Лучше написать

static bool getState(/*...*/);

здесь. Я попал в ту же ловушку (в стандарте есть формулировка, предполагающая, что статика файлов как-то устарела в пользу анонимных пространств имен), но работая в большом проекте C ++, таком как KDE, вы получаете множество людей, которые поворачивают голову правильно вокруг снова:)

9 голосов
/ 10 декабря 2008

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

Не так много преимуществ или недостатков, кроме "хочу ли я, чтобы эта переменная, функция, класс и т. Д. Были публичными или приватными?"

7 голосов
/ 26 мая 2016

Безымянное пространство имен ограничивает доступ класса, переменной, функции и объектов к файлу, в котором он определен. Безымянная функциональность пространства имен похожа на ключевое слово static в C / 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...