Кажется, существуют разные взгляды на использование слова using в отношении пространства имен std.
Некоторые говорят использовать ' using namespace std
', другие говорят, что нет, а вместо этого используют префикс std-функций, которые должны использоваться с ' std::
', в то время как другие говорят, что используйте что-то вроде этого:
using std::string;
using std::cout;
using std::cin;
using std::endl;
using std::vector;
для всех std-функций, которые будут использоваться.
Каковы плюсы и минусы каждого из них?
c++
namespaces
Паолорикардо
источник
источник
Ответы:
Большинство пользователей C ++ с удовольствием читают
std::string
,std::vector
и т.д. На самом деле, видя сырьеvector
заставляет меня задаться вопросом, является ли этоstd::vector
или другой определенный пользователемvector
.Я всегда против использования
using namespace std;
. Он импортирует всевозможные имена в глобальное пространство имен и может вызывать всевозможные неочевидные двусмысленности.Вот несколько общих идентификаторов, которые находятся в
std
пространстве имен: счетчик, сортировка, поиск, равенство, обратное. Имея локальную переменную с именемcount
означает, чтоusing namespace std
вы не сможете использовать ееcount
вместоstd::count
.Классический пример нежелательного конфликта имен выглядит примерно так. Представьте, что вы новичок и ничего не знаете
std::count
. Представьте, что вы либо используете что-то еще,<algorithm>
либо это связано с, казалось бы, несвязанным заголовком.Ошибка обычно длинная и недружелюбная, потому что
std::count
это шаблон с некоторыми длинными вложенными типами.Это нормально, потому что
std::count
входит в глобальное пространство имен, а счетчик функций скрывает его.Возможно, немного удивительно, но это нормально. Идентификаторы, импортированные в декларативную область видимости, появляются в общем пространстве имен, которое включает как место их определения, так и место их импорта. Другими словами,
std::count
виден какcount
в глобальном пространстве имен, но только внутриincrement
.И по схожим причинам
count
здесь неоднозначно.using namespace std
не вызываетstd::count
, спрячьте внешнее,count
как и следовало ожидать. Вusing namespace
правило означает , чтоstd::count
внешний вид (вincrement
функции) , как если бы он был объявлен в глобальном масштабе, то есть в том же объеме,int count = 0;
и , следовательно , вызывает неоднозначность.источник
using std::xxx;
. Он не загрязняет пространство имен, написание кода будет короче и, я думаюcopy
, намного более читаемым, чемstd::copy
.Исключение основ (необходимость добавления std :: infront всех объектов / функций stl и меньшая вероятность конфликта, если у вас нет 'using namespace std')
Также стоит отметить, что никогда не следует ставить
В файле заголовка, поскольку он может распространяться на все файлы, которые включают этот файл заголовка, даже если они не хотят использовать это пространство имен.
В некоторых случаях очень полезно использовать такие вещи, как
Как будто существует специализированная версия подкачки, компилятор будет использовать ее, иначе он вернется к
std::swap
.Если вы звоните
std::swap
, вы всегда используете базовую версию, которая не будет вызывать оптимизированную версию (если она существует).источник
using std::swap
(это единственное, что я когда-либо использовал).u n s
может распространяться. Просто обратите внимание, что он также может проникнуть в правильно построенные заголовки: их просто нужно включить после мошеннического заголовка.swap
илиmove
(илиhash
иless
т. Д.), Вамnamespace std
все равно следует включить эту специализацию . Например:namespace std {template<> class hash<X> {public: size_t operator()(const X&) const};} class X: {friend size_t std::hash<X>::operator()(const X&)};
Сначала немного терминологии:
using std::vector;
using namespace std;
Я думаю, что использование директив using - это нормально, если они не используются в глобальной области в файле заголовка. Так что имея
в вашем .cpp файле на самом деле не проблема, и если окажется, что это полностью под вашим контролем (и при желании его можно даже ограничить определенными блоками). Я не вижу особой причины загромождать код множеством
std::
квалификаторов - это просто становится кучей визуального шума. Однако, если вы не используетеstd
в своем коде целую кучу имен из пространства имен, я также не вижу проблем с исключением директивы. Это тавтология - если в директиве нет необходимости, то и использовать ее не нужно.Точно так же, если вы можете обойтись несколькими объявлениями using (вместо директив using ) для определенных типов в
std
пространстве имен, тогда нет причин, по которым вы не должны иметь только эти конкретные имена, перенесенные в текущее пространство имен. К тому же, я думаю, что было бы безумием и хлопотно иметь дело с 25 или 30 объявлениями using, когда одна директива using также подойдет.Также хорошо иметь в виду, что бывают случаи, когда вы должны использовать объявление using. Обратитесь к статье 25 Скотта Мейерса: подумайте о поддержке безбрасывающего свопа из Эффективного C ++, Третье издание. Чтобы универсальная шаблонная функция использовала «лучший» метод подкачки для параметризованного типа, вам необходимо использовать объявление с использованием объявления и поиск, зависящий от аргументов (также известный как ADL или поиск по Кенигу):
Я думаю, нам следует рассмотреть общие идиомы для различных языков, в которых значительно используются пространства имен. Например, Java и C # в значительной степени используют пространства имен (возможно, больше, чем C ++). Наиболее распространенный способ использования имен в пространствах имен на этих языках - их массовое внесение в текущую область действия с эквивалентом директивы using. Это не вызывает широко распространенных проблем, и в некоторых случаях проблема решается на основе «исключений», обрабатывая соответствующие имена с помощью полностью определенных имен или псевдонимов - точно так же, как это может быть сделано в C ++.
Херб Саттер и Андрей Александреску говорят об этом в «Правиле 59: Не записывайте использование пространств имен в заголовочный файл или перед #include» своей книги «Стандарты кодирования C ++: 101 правила, рекомендации и лучшие практики»:
Струпструп часто цитируется как сказал: «Не загрязняйте глобальное пространство имен» в «Языке программирования C ++, третье издание». Он действительно так говорит (C.14 [15]), но ссылается на главу C.10.1, где говорит:
И как получить такое же преимущество, как «ленивый пользователь глобальных имен»? Используя преимущество директивы using, которая безопасно делает имена в пространстве имен доступными для текущей области.
Обратите внимание, что есть различие - имена в
std
пространстве имен становятся доступными для области с правильным использованием директивы using (путем размещения директивы после#includes
) не загрязняют глобальное пространство имен. Это просто делает эти имена доступными и с постоянной защитой от столкновений.источник
std::
квалификаторы не загромождали код - есть другие способы избежать этого (обычно помогают объявления using или typedef).using namespace std;
директивы « » не мешает вам объявить свой естественный идентификатор 'list
' - просто если вы это сделаете, вы не сможете более длительное использованиеstd::list
без квалификации. Это ничем не отличается отusing namespace std;
директивы " ". Или я что-то упускаю?Никогда не используйте using namespace в глобальной области в файле заголовка. Это может привести к конфликту, и лицо, ответственное за файл, в котором возникает конфликт, не может повлиять на его причину.
В файле реализации варианты выбора гораздо хуже.
Ввод using namespace std приносит все символы из этих пространств имен. Это может быть неприятно, так как почти никто не знает все символы, которые есть (поэтому на практике невозможно применить политику отсутствия конфликтов), не говоря уже о символах, которые будут добавлены. А стандарт C ++ позволяет добавлять в заголовок символы из других заголовков (в C это не допускается). Он все еще может хорошо работать на практике для упрощения записи в контролируемых случаях. И если возникает ошибка, она обнаруживается в файле, в котором возникла проблема.
Ввод с использованием std :: name; имеет преимущество простоты написания без риска импорта неизвестных символов. Цена состоит в том, что вам необходимо явно импортировать все требуемые символы.
Явная квалификация добавляет немного беспорядка, но я думаю, что это меньше проблем с практикой.
В моем проекте я использую явную квалификацию для всех имен, я принимаю использование std :: name, я борюсь против использования пространства имен std (у нас есть интерпретатор lisp, который имеет свой собственный тип списка, и поэтому конфликт - это наверняка).
Для других пространств имен вы также должны учитывать используемые соглашения об именах. Я знаю проект, который использует пространство имен (для управления версиями) и префикс для имен. Выполнение
using namespace X
then почти без риска, и невыполнение этого приводит к глупо выглядящему кодуPrefixNS::pfxMyFunction(...)
.В некоторых случаях вы хотите импортировать символы. std :: swap - самый распространенный случай: вы импортируете std :: swap, а затем используете безусловный swap. Поиск, зависящий от аргумента, найдет соответствующий своп в пространстве имен типа, если он есть, и вернется к стандартному шаблону, если его нет.
Редактировать:
В комментариях Майкл Берр задается вопросом, происходят ли конфликты в реальном мире. Вот настоящий живой пример. У нас есть язык расширения с шепелявым диалектом. У нашего интерпретатора есть включаемый файл lisp.h, содержащий
Нам пришлось интегрировать и адаптировать некоторый код (который я назову «движок»), который выглядел так:
Итак, мы изменили так:
Хорошо. Все работает. Несколько месяцев спустя "module.h" был изменен и теперь включает "list.h". Испытания прошли. «модуль» не был изменен таким образом, чтобы это повлияло на его ABI, поэтому библиотеку «движка» можно было использовать без повторной компиляции ее пользователей. Интеграционные тесты прошли нормально. Опубликован новый «модуль». Следующая компиляция движка сломалась, когда его код не был изменен.
источник
Если у вас нет риска конфликта имен в вашем коде с std и другими библиотеками, вы можете использовать:
Но если вы хотите точно знать зависимость вашего кода от документации или существует риск конфликта имен, используйте другой способ:
Третье решение: не используйте эти решения и пишите std :: перед каждым использованием в коде, это дает вам больше безопасности, но, возможно, немного тяжелого кода ...
источник
Обе
и
добавить несколько символов (один или несколько) в глобальное пространство имен. А добавление символов в глобальное пространство имен - это то, чего вы никогда не должны делать в файлах заголовков. Вы не можете контролировать, кто будет включать ваш заголовок, есть много заголовков, которые включают другие заголовки (и заголовки, которые включают заголовки, которые включают заголовки, и так далее ...).
В файлах реализации (.cpp) это зависит от вас (только не забудьте сделать это после всех директив #include). Вы можете взломать только код в этом конкретном файле, чтобы было легче управлять и выяснить причину конфликта имен. Если вы предпочитаете использовать std :: (или любой другой префикс, в вашем проекте может быть много пространств имен) перед идентификаторами, все в порядке. Если вы хотите добавить идентификаторы, которые вы используете, в глобальное пространство имен, ничего страшного. Если вы хотите взять с собой все пространство имен :-), решать вам. Хотя эффекты ограничены одной единицей компиляции, это приемлемо.
источник
Лично я предпочитаю использовать,
::
когда это возможно.Ненавижу писать:
Надеюсь, с C ++ 0x я напишу это:
Если пространство имен очень длинное,
источник
++i
, а неi++
потому, что, если он даже определен, создает ненужную временную копию итератора.Вы никогда не должны находиться
using namespace std
в области пространства имен в заголовке. Кроме того, я полагаю, что большинство программистов задаются вопросом, когда они увидятvector
илиstring
нетstd::
, так что я думаю, что неusing namespace std
лучше. Поэтому я утверждаю, что никогда не будетusing namespace std
.Если вы чувствуете, что должны, добавьте локальные объявления using, например
using std::vector
. Но спросите себя: чего это стоит? Строка кода пишется один раз (может быть, дважды), но читается десять, сотни или тысячи раз. Сэкономленные усилия при вводе объявления или директивы using незначительны по сравнению с усилиями чтения кода.Имея это в виду, в проекте десять лет назад мы решили явно квалифицировать все идентификаторы их полными именами пространств имен. То, что сначала казалось неудобным, через две недели превратилось в рутину. Теперь во всех проектах этой компании больше никто не использует директивы или декларации using. (За одним исключением, см. Ниже.) Глядя на код (несколько MLoC) через десять лет, я чувствую, что мы приняли правильное решение.
Я обнаружил, что обычно те, кто выступает против запрета,
using
обычно не пробовали это для одного проекта. Те, кто пробовал, часто находят это лучше, чем использование директив / деклараций через очень короткое время.Примечание. Единственное исключение - это то,
using std::swap
что необходимо (особенно в универсальном коде) для сбора перегрузок,swap()
которые нельзя поместить вstd
пространство имен (поскольку нам не разрешено помещать перегрузкиstd
функций в это пространство имен).источник
std
, но не перегружать. Извините за этот тупик. Пост поправлю.using namespace
директивы было также вводить текст ; скорее, это было сделано для облегчения чтения , потому что, как вы говорите, этот код придется читать десятки, сотни или тысячи раз. А для некоторых людей он читается намного проще и меньшеstd::
беспорядка. Но это, вероятно, сводится к личной способности восприятия; некоторые люди отфильтровываютstd::
или даже нуждаются в нем в качестве руководства (например, с засечками), другие спотыкаются и чувствуют себя как на ухабистой дороге.Пространства имен содержат код, чтобы предотвратить путаницу и загрязнение сигнатур функций.
Вот полная и документированная демонстрация правильного использования пространства имен :
Вывод:
источник
using namespace std
импортирует содержимоеstd
пространства имен в текущее. Таким образом, преимущество заключается в том, что вам не придется вводитьstd::
текст перед всеми функциями этого пространства имен. Однако может случиться так, что у вас есть разные пространства имен, которые имеют функции с одинаковыми именами. Таким образом, вы можете перестать звонить тому, кого хотите.Указание вручную, какие из них вы хотите импортировать,
std
предотвратит это, но может привести к появлению длинного списка использования в начале вашего файла, что некоторые разработчики сочтут уродливыми;)!Лично я предпочитаю указывать пространство имен каждый раз, когда я использую функцию, за исключением случаев, когда пространство имен слишком длинное, и в этом случае я помещаю некоторые using в начало файла.
РЕДАКТИРОВАТЬ: как указано в другом ответе, вы никогда не должны помещать a
using namespace
в файл заголовка, поскольку он будет распространяться на все файлы, включая этот заголовок, и, таким образом, может вызвать нежелательное поведение.EDIT2: исправил мой ответ, благодаря комментарию Чарльза.
источник
using namespace std;
импортирует содержимоеstd
пространства имен в глобальное пространство имен. Это не меняет пространство имен по умолчанию. Определение чего-либо в глобальном пространстве имен после ausing namespace std
не волшебным образом поместит это вstd
пространство имен.Как и в Java, где вы можете использовать либо включить java.util. *, Либо просто выбрать каждый класс индивидуально, это зависит от стиля. Обратите внимание, что вы не хотите, чтобы он был
using namespace std
в начале вашего файла / широкой области, потому что вы загрязните пространство имен и, возможно, столкнетесь с конфликтами, побеждая точку пространств имен. Но если у вас есть функция, которая использует много STL, она загромождает код, чтобы иметь беспорядочный синтаксис префиксов в вашей логике, и вам, вероятно, следует рассмотреть возможность использования либоusing namespace std
(при использовании множества классов), либо отдельныхusing
s (при использовании нескольких занятия часто).источник
Это обсуждение будет продолжаться до тех пор, пока IDE, с которой вы работаете, не будет достаточно гибкой, чтобы отображать или скрывать точную информацию, которая вам нужна.
Это потому, что то, как вы хотите, чтобы ваш код выглядел, зависит от решаемой задачи.
При создании исходного кода я предпочитаю видеть, какой именно класс я использую: это
std::string
илиBuzFlox::Obs::string
класс?При проектировании потока управления меня даже не интересуют типы переменных, но я хочу сосредоточиться на
if
's иwhile
' иcontinue
's.Итак, это мой совет:
В зависимости от аудитории вашего кода и мощности ваших инструментов выберите способ, который либо удобнее читать, либо дает больше информации.
источник
Есть несколько способов исправить это.
Первое: используйте то же, что и вы.
Во-вторых: сделать
namespace S = std;
, уменьшив 2 символа.Третье: использование
static
.Четвертое: не используйте имена, которые
std
используют.источник
Единственная причина отказаться от std :: заключается в том, что теоретически вы можете самостоятельно реализовать все функции STL. Тогда ваши функции можно будет переключить с использования std :: vector на my :: vector без изменения кода.
источник
Почему бы не например
вместо громоздкого
Я считаю, что это гораздо более читабельно, и это мой стандарт кодирования.
Вы даже можете использовать его для включения некоторой семантической информации для читателя. Например, рассмотрим прототипы функций
какие из них возвращаемое значение?
Как насчет вместо
источник