Что такое «использование пространства имен»?


15

Я искал руководство по программированию Google [здесь], и они не рекомендуют использовать один using namespaceили namespace::function- если я не истолковал его неправильно.

Это относится и к std? cout<<не работает без него. Эта книга рекомендует то же самое. Так как же мне использовать cout<<без using namespace std;или std::cout<<?

Какой рекомендуемый способ? std::cout<<? Большинство учебников по c ++ учат начинающих using namespace std;, пропагандируют ли они плохую практику кодирования?

Ответы:


18

Поскольку я читаю стандарт Google, вы using namespace foo;нигде не можете использовать директиву. Эта директива вводит все, что объявлено в пространстве имен, и является частой причиной коллизий и неожиданного поведения. Другие приводят очень распространенный метод: у вас где-то есть собственный метод max или min, и он сталкивается в файле src, где кто-то включает заголовок в ваш метод и затем говорит:using namespace std;

В некоторых местах разрешено иметь декларацию об использовании, которая имеет вид using ::foo::bar;

Людям нравится помещать директивы использования в их код, потому что это экономит много времени на печатание, но сопряжено с риском. Если у вас есть файл с множеством операторов cout, я могу понять, что вам не нужно вводить std :: cout сто раз, но вы можете просто сказать, используя :: std :: cout. Я отношусь к ним как к объявлениям переменных: определяйте их там, где они необходимы. Если одной функции в файле из 10 нужно записать вывод, не объявляйте путь cout вверху, поместите его в ту функцию, которая выполняет фактический вывод.

#include <ostream>
//using namespace std; // NO!
//using ::std::cout;   // less bad than using namespace, but I prefer to scope it

int main(int argc, char** argv)
{
   int rc = do_some_stuff(argc, argv);
   using ::std::endl;
   if (rc) { // print the success report
      using ::std::cout;
      cout << "The test run completed. The return code was " << rc << '.' << endl;
    } else {
      using ::std::cerr;
      cerr << "Unable to complete the test run." << endl;
    }
    return 0 == rc;
}

Это немного экстремально, когда всего несколько строк делают вывод, но вы поняли идею.

Другая вещь, которую можно сделать, это псевдоним или typedef, чтобы минимизировать набор текста. Я не считаю, что std :: что-то плохое, но у нас есть огромный набор исходников с несколькими десятками модулей, и иногда нам приходится писать такой код console_gui::command_window::append("text"). Это становится утомительным через некоторое время и вызывает много длинных очередей. Я все за что-то вроде

typedef console_gui::command_window cw;
cw::append("text");

до тех пор, пока псевдонимы выполняются в локальной области и содержат достаточно контекста, чтобы сделать код читабельным.


1
Благодарность! Это действительно полезно. Вы не только объяснили, почему это плохо с хорошими примерами, но и указали решения с хорошими примерами. :-)
Лорд Лох.

1
Кстати: использование std::endlдля явного сброса на stdout/ stderrобычно довольно излишне, эти потоки связаны с stdout/ в stderrлюбом случае. Это даже немного замедляет ход событий.
дедупликатор

8

Это связано с тем, что: 1) он побеждает всю цель пространств имен, которая заключается в уменьшении коллизий имен; 2) он делает доступным для глобального пространства имен все пространство имен, указанное в директиве using.

Например, если вы включите и определите свою собственную функцию max (), она столкнется с std :: max ().

http://en.cppreference.com/w/cpp/algorithm/max

Предпочтение отдается использованию std :: member_you_wish_to_use, поскольку оно явно указывает, какое пространство имен использовать.


Я предполагаю, что это означает, что я должен использовать std::max()с префиксом пространства имен. Или я ошибаюсь?
Лорд Ло.

3
Это означает, что если вы поставите «использование пространства имен std;» в вашем коде вы получите ошибки, если определите свою собственную функцию max (или любое другое имя, уже определенное в пространстве имен std)
Chewy Gumball

1
Это просто означает, что вы должны быть осторожны с usingдирективами, потому что в этом случае она сломает вашу функцию max (), если вы ее определили и включили <алгоритм>. Это простой случай, но вы никогда не знаете, что вы можете сломать. Вам нужно было бы знать всю библиотеку, чтобы быть уверенным, что вы не сломали ее, но вы не можете знать, сломается ли ваш код (то есть столкновение имен) в будущем.
ApplePie

6

Цитируя ссылку, которую вы предоставляете:

Вы можете использовать декларацию использования в любом месте файла .cc, а также в функциях, методах или классах в файлах .h.

// ОК в .cc файлах.

// Должен быть в функции, методе или классе в .h файлах.

используя :: foo :: bar;

Стиль Google запрещает вам использовать импорт пространств имен в глобальном контексте, но позволяет делать это в локальных.

Везде, где использование объявления затрагивает только ограниченную и четко видимую часть кода, это вполне приемлемо.

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


У нас одинаковые стандарты. Некоторые из наших людей будут локально печатать длинные имена. например, typedef foolicious :: barlicious fb; fb :: drink d;
Майкл Мэтьюз

1

они не рекомендуют использовать использование пространства имен или пространства имен: функция` - если я не неправильно его интерпретировал.

Ты сделал. Эта рекомендация относится только к using namespaceдирективе (которая обычно называется abusing namespaceне совсем смешно). Настоятельно рекомендуется использовать полное имя функции или объекта, например std::cout.


1

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

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

Идентификаторы в пространствах имен доступны путем явного именования пространства имен:

myNamespace::myIdent

это может быть намного больше ключей для ввода. Но это также может снизить значимость вашего кода, если большинство идентификаторов получат префикс одинаковым образом. usingКлючевое слово помогает предотвратить эти пространства имен недостатков. Так как usingработает на уровне компилятора (это не макрос), его эффект действует для всей области, в которой он используется. Поэтому стиль Google ограничивает его использование четко определенными областями, то есть классами в заголовочных файлах или функциями в файлах cpp.

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

using myNamespace::myIdent; // make myIdent an alias of myNamespace::myIdent

и используя директиву

using myNamespace; // make all identifiers of myNamespace directly accessible

При использовании в огромных масштабах последнее приводит к гораздо большей путанице.


1

Ну вот:

#include <iostream>

int main()
{
    std::endl(std::operator<<(std::cout, "Hello world!"));
}

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

Это должно быть саркастическим ответом. :-D

Я с Хербом Саттером из-за Google. Из C ++ Стандарты кодирования:

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

Вы можете зацикливаться на потенциальных конфликтах пространства имен, которые, вероятно, никогда не проявятся, и, вероятно, их не будет трудно исправить в таком астрономически редком событии, осторожно избегая usingдиректив и явно указывая каждую вещь, которую вы используете (вплоть до операторов) с usingобъявлениями, или просто идти вперед и начать using namespace std. Я рекомендую последний с точки зрения производительности.

Большинство учебников по c ++ обучают новичков использованию пространства имен std; они распространяют плохую практику кодирования?

Наоборот, если вы спросите меня, и я считаю, что Саттер выше соглашается.

Теперь, в течение моей карьеры, я столкнулся примерно с 3 конфликтами пространства имен как прямой результат usingдиректив в кодовых базах, охватывающих десятки миллионов LOC. Однако во всех трех случаях они были в исходных файлах, которые занимали более 50000 строк устаревшего кода, первоначально написанного на C, а затем подвергнутого разбору на C ++, выполняющего огромный эклектичный список разрозненных функций, включая заголовки из дюжины различных библиотек и имеющие эпический список того, #includesчто охватило всю страницу. Несмотря на эпический беспорядок, их было не слишком сложно исправить, поскольку они вызывали ошибки сборки на OSX (единственной ОС, где код не удалось собрать), а не ошибки времени выполнения. Не организовывайте свой код таким кошмарным образом, и все будет в порядке.

Тем не менее, во избежание обе using директивы и объявления в заголовочных файлах. Это просто отсталый. Но для исходных файлов, особенно для тех, у которых нет целой страницы, заполненной #includeдирективами, я бы сказал, не переживайте, если вы не работаете в Google.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.