Почему используются неименованные пространства имен и каковы их преимущества?

Я только что присоединился к новому проекту программного обеспечения 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 больше не делает почти никаких различий (если они есть, это просто языковые различия, которые я не могу вспомнить).).

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

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С ЕП местных и не столкновение во время ссылки. Но разница в том, что 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; 

параметры шаблона должны иметь внешнюю связь, поэтому в этом случае идентификатор должен быть помещен в анонимное пространство имен.

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


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

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

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

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*);
}

и это на самом деле pessimisation: 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