Почему не стоит использовать using namespace std
Перейти к содержимому

Почему не стоит использовать using namespace std

Пространство имен (using namespace std;)

Очень часто в интернете вижу как многие программисты усердно пишут везде программы используя в коде std:: . Зачем они это делают? Почему нельзя просто использовать using namespace std; перед программой, так же удобнее и код начинает «дышать». Или это плохой тон и стоит переучиваться на использование std:: непосредственно в коде программы?

Зависит от традиций. Среди плюсовиков традиция «лучше перестраховаться, чем получить внезапные трудно отлаживаемые проблемы неизвестно где».

Явное указание пространства имён — это избавление от потенциальных проблем в будущем. Положим, вы подключили через using namespace два пространства имён. Всё замечательно, кратко, красиво.

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

В лучшем случае ваш код не соберётся. Может упасть. А может так получиться, что ваш код перестанет работать у клиента в 1% случаев. Всё может быть.

Отлавливать и исправлять подобные проблемы мучительно больно.

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

Банальный пример: положим, вы пользуетесь только стандартной библиотекой и boost, поэтому решили везде писать:

. а теперь выходит новая версия стандартной библиотеки, в которой из boost перетащено много классов. И внезапно ваш код больше не компилируется.

В других языках другие традиции. Например, в C# почти всегда пишут краткие имена классов, и только в случае конфликтов явно указывают пространство имён или используют алиасы. Язык немного отличается: там нет функций вне классов. Это позволяет меньше терять читаемость и реже натыкаться на неожиданные конфликты.

Почему с ‘using namespace std;’ в *.cpp-файлах может быть очень плохо

То, что написано ниже, для многих квалифицированных C++ разработчиков будет прекрасно известным и очевидным, но тем не менее, я периодически встречаю using namespace std; в коде различных проектов, а недавно в нашумевшей статье про впечатления от высшего образования было упомянуто, что студентов так учат писать код в вузах, что и сподвигло меня написать эту заметку.

Итак. многие слышали, что using namespace std; в начале файла в C++ считается плохой практикой и нередко даже явно запрещен в принятых во многих проектах стандартах кодирования. Касательно недопустимости использования using namespace в header-файлах вопросов обычно не возникает, если мы хоть немного понимаем, как работает препроцессор компилятора: .hpp-файлы при использовании директивы #include вставляются в код «как есть», и соответственно using автоматически распространится на все затронутые .hpp- и .cpp-файлы, если файл с ним был заинклюден хоть в одном звене цепочки (на одном из сайтов это метко обозвали «заболеванием передающимся половым путем«). Но вот про .cpp-файлы все не так очевидно, так что давайте еще раз разберем, что же именно здесь не так.

Для чего вообще придумали пространства имен в C++? Когда какие-то две сущности (типы, функции, и т.д.) имеют идентификаторы, которые могут конфликтовать друг с другом при совместном использовании, C++ позволяет объявлять пространства с помощью ключевого слова namespace. Всё, что объявлено внутри пространства имен, принадлежит только этому пространству имен (а не глобальному). Используя using мы вытаскиваем сущности какого-либо пространства имен в глобальный контекст.

А теперь посмотрим, к чему это может привести.

Допустим, вы используете две библиотеки под названием Foo и Bar и написали в начале файла что-то типа

. таким образом вытащив всё, что есть в foo:: и в bar:: в глобальное пространство имен.

Все работает нормально, и вы можете без проблем вызвать Blah() из Foo и Quux() из Bar. Но однажды вы обновляете библиотеку Foo до новой версии Foo 2.0, которая теперь еще имеет в себе функцию Quux().

Теперь у вас конфликт: и Foo 2.0, и Bar импортируют Quux() в ваше глобальное пространство имен. В лучшем случае это вызовет ошибку на этапе компиляции, и исправление этого потребует усилий и времени.

А вот если бы вы явно указывали в коде метод с его пространством имен, а именно, foo::Blah() и bar::Quux(), то добавление foo::Quux() не было бы проблемой.

Но всё может быть даже хуже!

В библиотеку Foo 2.0 могла быть добавлена функция foo::Quux(), про которую компилятор по ряду причин посчитает, что она однозначно лучше подходит для некоторых ваших вызовов Quux(), чем bar::Quux(), вызывавшаяся в вашем коде на протяжении многих лет. Тогда ваш код все равно скомпилируется, но будет молча вызывать неправильную функцию и делать бог весть что. И это может привести к куче неожиданных и сложноотлаживающихся ошибок.

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

Если вы считаете это маловероятным, то посмотрим на реальные примеры со stackoverflow:

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

Второй пример на ту же тему: вместо функции swap() используется std::swap(). Опять же, никакой ошибки компиляции, а просто неправильный результат работы.

Почему «using namespace std;» считается плохой практикой?

Другие говорили мне, что писать using namespace std; в коде неправильно и что я должен использовать вместо него напрямую std::cout и std::cin .

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

30 ответов

Это вообще не связано с производительностью. Но учтите: вы используете две библиотеки под названием Foo и Bar:

Все работает нормально, и вы можете без проблем вызвать Blah() из Foo и Quux() из Bar. Но однажды вы обновитесь до новой версии Foo 2.0, которая теперь предлагает функцию под названием Quux() . Теперь у вас конфликт: и Foo 2.0, и Bar импортируют Quux() в ваше глобальное пространство имен. Это потребует некоторых усилий, чтобы исправить, особенно если параметры функции совпадают.

Если бы вы использовали foo::Blah() и bar::Quux() , то введение foo::Quux() не было бы событием.

Я согласен со всем, что Грег написал, но хочу добавить: Может даже хуже, чем сказал Грег!

Библиотека Foo 2.0 могла бы представить функцию Quux() , которая однозначно лучше подходит для некоторых ваших вызовов Quux() , чем bar::Quux() , который ваш код вызывал годами. Тогда ваш код по-прежнему компилируется , но молча вызывает неправильную функцию и делает бог знает что. Это настолько плохо, насколько это вообще возможно.

Имейте в виду, что пространство имен std имеет множество идентификаторов, многие из которых являются очень распространенными (подумайте list , sort , string , iterator и т. Д.), Которые, скорее всего, тоже появятся в другом коде.

Если вы считаете это маловероятным: здесь, в Stack Overflow, был вопрос, заданный, где в значительной степени именно это и произошло (неправильная функция вызвана из-за на опущенный префикс std:: ) примерно через полгода после того, как я дал этот ответ. Вот еще один, более свежий пример такого вопроса. Так что это настоящая проблема.

Вот еще один факт: много-много лет назад меня раздражало то, что все элементы стандартной библиотеки добавлялись в префикс std:: . Затем я работал в проекте, где с самого начала было решено, что и директивы using , и объявления запрещены, за исключением областей видимости функций. Угадай, что? Большинству из нас потребовалось всего несколько недель, чтобы привыкнуть к написанию префикса, и еще через несколько недель большинство из нас даже согласилось, что это действительно сделало код более читабельным . Для этого есть причина: Нравится вам более короткая или более длинная проза — это субъективно, но префиксы объективно добавляют ясности коду. Не только компилятор, но и вы тоже. легче понять, к какому идентификатору идет речь.

За десять лет этот проект вырос до нескольких миллионов строк кода. Поскольку эти обсуждения возникают снова и снова, мне когда-то было любопытно, как часто (разрешенная) область видимости функции using фактически использовалась в проекте. Я поискал его в источниках и нашел только один или два десятка мест, где он использовался. На мой взгляд, это означает, что после попытки разработчики не находят std:: достаточно болезненным, чтобы использовать директивы using даже один раз на каждые 100 kLoC, даже если это разрешено.

Итог: явное добавление префиксов ко всему не приносит никакого вреда, требует очень небольшого привыкания и имеет объективные преимущества. В частности, это упрощает интерпретацию кода компилятором и читателями — и это, вероятно, должно быть основной целью при написании кода.

Проблема с помещением using namespace в файлы заголовков ваших классов заключается в том, что это заставляет любого, кто хочет использовать ваши классы (включая ваши файлы заголовков), также «использовать» (т.е. видеть все в) эти другие пространства имен.

Однако вы можете свободно помещать оператор using в свои (личные) файлы * .cpp.

Имейте в виду, что некоторые люди не согласны с моим высказыванием «не стесняйтесь», потому что хотя оператор using в файле cpp лучше , чем в заголовке (потому что он не влияет на людей кто включает ваш файл заголовка), они думают, что это все еще не хорошо (потому что в зависимости от кода это может затруднить поддержку реализации класса). В этой записи C ++ Super-FAQ говорится:

Директива using существует для устаревшего кода C ++ и для облегчения перехода к пространствам имен, но вам, вероятно, не следует использовать ее на регулярной основе, по крайней мере, в вашем новом коде C ++.

FAQ предлагает две альтернативы:

Просто наберите std ::

Недавно я столкнулся с жалобой на Visual Studio 2010. Оказалось, что почти все исходные файлы содержат эти две строки:

Многие функции Boost входят в C ++ 0x стандарт, а Visual Studio 2010 имеет множество функций C ++ 0x, поэтому внезапно эти программы перестали компилироваться.

Следовательно, избегание using namespace X; — это форма защиты от будущего, способ убедиться, что изменение используемых библиотек и / или файлов заголовков не приведет к поломке программы.

Краткая версия: не используйте глобальные объявления или директивы using в файлах заголовков. Не стесняйтесь использовать их в файлах реализации. Вот что Herb Sutter и Андрей Александреску должен сказать об этой проблеме в Стандарты кодирования C ++ (выделено мной жирным шрифтом):

Резюме

Использование пространства имен предназначено для вашего удобства, а не для того, чтобы вы навязывали его другим: никогда не пишите объявление using или директиву using перед директивой #include.

Следствие: в файлах заголовков не записывайте уровень пространства имен с помощью директив или с помощью объявлений; вместо этого явно уточняйте все имена по пространству имен. (Второе правило следует из первого, потому что заголовки никогда не могут знать, какой другой заголовок #includes может появиться после них.)

Обсуждение

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

Не следует использовать директиву using в глобальной области видимости, особенно в заголовках. Однако бывают ситуации, когда это уместно даже в файле заголовка:

Это лучше, чем явная квалификация ( std::sin , std::cos . ), потому что она короче и позволяет работать с определяемыми пользователем типами с плавающей запятой (через поиск по аргументам (ADL)).

Не используйте его глобально

Он считается «плохим» только при глобальном использовании . Потому что:

  • Вы загромождаете пространство имен, в котором программируете.
  • Читателям будет сложно понять, откуда берется тот или иной идентификатор, когда вы используете много using namespace xyz .
  • Все, что верно для других читателей вашего исходного кода, еще более верно для наиболее частого читателя: для вас самих. Вернитесь через год или два и посмотрите .
  • Если вы говорите только о using namespace std , вы можете не знать обо всем, что вы захватываете — и когда вы добавляете еще один #include или переходите к новой ревизии C ++, вы можете получить конфликты имен, о которых вы не знали .

Вы можете использовать его локально

Идите вперед и используйте его локально (почти) свободно. Это, конечно, предотвращает повторение std:: — и повторение тоже плохо.

Идиома для локального использования

В C ++ 03 была идиома — шаблонный код — для реализации функции swap для ваших классов. Было предложено использовать локальный using namespace std — или хотя бы using std::swap :

Это творит следующую магию:

  • Компилятор выберет std::swap для value_ , то есть void std::swap(int, int) .
  • Если у вас реализована перегрузка void swap(Child&, Child&) , компилятор выберет ее.
  • Если у вас нет этой перегрузки, компилятор будет использовать void std::swap(Child&,Child&) и постарается заменить их местами.

В C ++ 11 больше нет причин использовать этот шаблон. Реализация std::swap была изменена, чтобы найти потенциальную перегрузку и выбрать ее.

Если вы импортируете правильные файлы заголовков, у вас внезапно появятся имена вроде hex , left , plus или count в вашей глобальной области. Это может быть удивительно, если вы не знаете, что std:: содержит эти имена. Если вы также попытаетесь использовать эти имена локально, это может привести к некоторой путанице.

Если все стандартные вещи находятся в собственном пространстве имен, вам не нужно беспокоиться о конфликтах имен с вашим кодом или другими библиотеками.

Другая причина — неожиданность.

Если я вижу cout << blah вместо std::cout << blah , я думаю: что это за cout ? Это нормальный cout ? Это что-то особенное?

Опытные программисты используют все, что решает их проблемы, и избегают того, что создает новые проблемы, и они избегают директив using на уровне заголовочного файла именно по этой причине.

Опытные программисты также стараются избегать полной квалификации имен в своих исходных файлах. Второстепенная причина этого заключается в том, что писать больше кода, когда достаточно меньше кода, неуместно , если для этого нет веских причин . Основная причина этого — отключение поиска, зависимого от аргументов (ADL).

Каковы эти веские причины ? Иногда программисты явно хотят отключить ADL, иногда они хотят устранить неоднозначность.

Итак, все в порядке:

  1. Директивы использования и объявления на уровне функций внутри реализаций функций
  2. Объявления использования на уровне исходного файла внутри исходных файлов
  3. (Иногда) директивы использования на уровне исходного файла

Я согласен с тем, что его не следует использовать глобально, но не так уж плохо использовать его локально, как в namespace . Вот пример из «Язык программирования C ++» :

В этом примере мы разрешили потенциальные конфликты имен и неоднозначности, связанные с их составом.

Имена, явно объявленные там (включая имена, объявленные с помощью объявлений-использования, таких как His_lib::String ), имеют приоритет над именами, доступными в другой области с помощью директивы-использования ( using namespace Her_lib ).

Я тоже считаю это плохой практикой. Почему? Как-то раз я подумал, что функция пространства имен — разделять вещи, поэтому мне не следует портить его, бросая все в один глобальный мешок.

Однако, если я часто использую cout и cin, я пишу: using std::cout; using std::cin; в файле .cpp (никогда в файле заголовка, поскольку он распространяется с #include ). Я думаю, что ни один здравомыслящий человек никогда не назовет поток cout или cin . 😉

Приятно видеть код и знать, что он делает. Если я вижу std::cout , я знаю, что это поток cout библиотеки std . Если я увижу cout , то не знаю. Это может быть потоком cout библиотеки std . Или в той же функции может быть int cout = 0; на десять строк выше. Или переменную static с именем cout в этом файле. Это могло быть что угодно.

Теперь возьмите базу кода из миллиона строк, которая не особенно велика, и вы ищете ошибку, что означает, что вы знаете, что в этом миллионе строк есть одна строка, которая не выполняет то, что должна делать. cout << 1; может прочитать static int с именем cout , сдвинуть его влево на один бит и выбросить результат. Ищу ошибку, я должен это проверить. Вы видите, как я действительно предпочитаю видеть std::cout ?

Это одна из тех вещей, которые кажутся действительно хорошей идеей, если вы учитель, и вам никогда не приходилось писать и поддерживать какой-либо код, чтобы заработать себе на жизнь. Мне нравится видеть код, в котором (1) я знаю, что он делает; и (2) я уверен, что человек, написавший это, знал, что он делает.

Все дело в управлении сложностью. Использование пространства имен втянет в себя вещи, которые вам не нужны, и, возможно, затруднит отладку (я говорю, возможно). Использование std :: повсюду труднее для чтения (больше текста и все такое).

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

Конкретный пример, чтобы прояснить проблему. Представьте, что у вас есть две библиотеки, foo и bar , каждая со своим собственным пространством имен:

Теперь предположим, что вы используете foo и bar вместе в своей собственной программе следующим образом:

На данный момент все в порядке. Когда вы запускаете свою программу, она «что-то делает». Но позже вы обновите bar , и скажем, он изменился на:

На этом этапе вы получите ошибку компилятора:

Так что вам нужно будет немного поработать, чтобы уточнить, что «а» означает foo::a . Это нежелательно, но, к счастью, это довольно просто (просто добавьте foo:: перед всеми вызовами a , которые компилятор помечает как неоднозначные).

Но представьте себе альтернативный сценарий, в котором bar вместо этого изменился и стал выглядеть так:

В этот момент ваш вызов a(42) внезапно привязывается к bar::a вместо foo::a , и вместо того, чтобы делать что-то, он делает что-то совершенно другое. Никаких предупреждений компилятора или чего-то подобного. Ваша программа просто незаметно начинает делать что-то совершенно иное, чем раньше.

Когда вы используете пространство имен, вы рискуете подобным сценарием, поэтому людям неудобно использовать пространства имен. Чем больше элементов в пространстве имен, тем выше риск конфликта, поэтому людям может быть еще более неудобно использовать пространство имен std (из-за количества элементов в этом пространстве имен), чем другие пространства имен.

В конечном итоге это компромисс между возможностью записи и надежностью / ремонтопригодностью. Читаемость также может иметь значение, но я видел аргументы в пользу этого в любом случае. Обычно я бы сказал, что надежность и ремонтопригодность более важны, но в этом случае вы будете постоянно платить за возможность записи за довольно редкое влияние на надежность / ремонтопригодность. «Лучший» компромисс определит ваш проект и ваши приоритеты.

Использование множества пространств имен одновременно, очевидно, может привести к катастрофе, но использование JUST пространства имен std и только пространства имен std , на мой взгляд, не так уж важно, потому что переопределение может происходить только с помощью вашего собственного кода. .

Так что просто считайте их функции зарезервированными именами, такими как «int» или «class», и все.

Люди должны перестать быть такими анальными по этому поводу. Ваш учитель был прав с самого начала. Просто используйте ОДНО пространство имен; в этом весь смысл использования пространств имен в первую очередь. Вы не должны использовать более одного одновременно. Если только это не твое собственное. Итак, повторного определения не произойдет.

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

Если вы используете только cout , никто не запутается. Но когда у вас много летающих пространств имен, и вы видите этот класс, но не совсем уверены, что он делает, наличие явного пространства имен действует как своего рода комментарий. С первого взгляда вы можете увидеть: «О, это операция файловой системы» или «Это работает с сетью».

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

Я обычно использую его в своем объявлении класса, поскольку методы в классе имеют тенденцию иметь дело с похожими типами данных (членами), а typedef — это возможность присвоить имя, которое имеет смысл в контексте класса. Это на самом деле способствует удобочитаемости определений методов класса.

Пространство имен — это именованная область. Пространства имен используются для группировки связанных объявлений и для разделения отдельных элементов. Например, две отдельно разработанные библиотеки могут использовать одно и то же имя для обозначения разных элементов, но пользователь все равно может использовать оба:

Повторение имени пространства имен может отвлекать как читателей, так и писателей. Следовательно, можно утверждать, что имена из определенного пространства имен доступны без явной квалификации. Например:

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

Источник: Обзор языка программирования C ++ Бьярне Страуструп

Пример, в котором using namespace std выдает ошибку компиляции из-за неоднозначности счетчика, который также является функцией в библиотеке алгоритмов.

Это не ухудшает производительность вашего программного обеспечения или проекта. Включение пространства имен в начало исходного кода неплохо. Включение инструкции using namespace std зависит от ваших потребностей и способа разработки программного обеспечения или проекта.

namespace std содержит стандартные функции и переменные C ++. Это пространство имен полезно, когда вы часто будете использовать стандартные функции C ++.

Как указано на этой странице:

Оператор, использующий пространство имен std, обычно считается плохой практикой. Альтернативой этому оператору является указание пространства имен, которому принадлежит идентификатор, с помощью оператора области видимости (: 🙂 каждый раз, когда мы объявляем тип.

И см. это мнение:

Нет проблем с использованием «using namespace std» в исходном файле, когда вы интенсивно используете пространство имен и точно знаете, что ничего не произойдет.

Некоторые люди сказали, что включать using namespace std в исходные файлы — плохая практика, потому что вы вызываете из этого пространства имен все функции и переменные. Если вы хотите определить новую функцию с тем же именем, что и другая функция, содержащаяся в namespace std , вы должны перегрузить функцию, и это может вызвать проблемы из-за компиляции или выполнения. Он не будет компилироваться или выполняться так, как вы ожидаете.

Как указано на этой странице:

Хотя этот оператор избавляет нас от ввода std :: всякий раз, когда мы хотим получить доступ к классу или типу, определенным в пространстве имен std, он полностью импортирует пространство имен std в текущее пространство имен программы. Давайте рассмотрим несколько примеров, чтобы понять, почему это может быть не так хорошо.

.

Теперь, на более позднем этапе разработки, мы хотим использовать другую версию cout, которая специально реализована в некоторой библиотеке под названием «foo» (например)

.

Обратите внимание на неоднозначность, на какую библиотеку указывает cout? Компилятор может обнаружить это и не скомпилировать программу. В худшем случае программа все еще может компилироваться, но вызывать неправильную функцию, поскольку мы никогда не указывали, какому пространству имен принадлежит идентификатор.

Это от случая к случаю. Мы хотим минимизировать «общую стоимость владения» программного обеспечения на протяжении его срока службы. Утверждение «using namespace std» требует определенных затрат, но отсутствие его использования также требует затрат на удобочитаемость.

Люди правильно отмечают, что при его использовании, когда стандартная библиотека вводит новые символы и определения, ваш код перестает компилироваться, и вы можете быть вынуждены переименовать переменные. И все же это, вероятно, хороший долгий срок, так как будущие сопровождающие на мгновение будут сбиты с толку или отвлечены, если вы используете ключевое слово для какой-то неожиданной цели.

Вы не хотите иметь шаблон с именем, скажем, вектор, который не известен всем остальным. И количество новых определений, введенных таким образом в библиотеку C ++, достаточно мало, поэтому может просто не появиться. За внесение такого рода изменений приходится платить, но цена невысока и компенсируется ясностью, достигнутой за счет отказа от использования имен символов std для других целей.

Учитывая количество классов, переменных и функций, указание std:: для каждого из них может испортить ваш код на 50% и усложнить понимание. Алгоритм или шаг в методе, который можно было бы использовать на одном экране, полный кода, теперь требует прокрутки назад и вперед, чтобы следовать. Это реальная стоимость. Возможно, это может быть невысокая цена, но люди, которые отрицают, что это вообще существует, неопытны, догматичны или просто ошибаются.

Предлагаю следующие правила:

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

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

Несмотря на то, что функция пространства имен позволяет вам иметь много модулей с одинаковыми символами, это будет сбивать с толку. По возможности используйте разные имена. Даже если вы не используете функцию пространства имен, если у вас есть класс с именем foo и std вводит класс с именем foo , вероятно, в долгосрочной перспективе лучше все равно переименовать ваш класс.

Альтернативой использованию пространств имен является ручное добавление символов пространств имен к ним. У меня есть две библиотеки, которые я использовал на протяжении десятилетий, причем обе начинались как библиотеки C, где каждый символ имеет префикс «AK» или «SCWin». Вообще говоря, это похоже на отказ от конструкции using, но вы не пишете двойные двоеточия. AK::foo() вместо AKFoo() . Это делает код на 5-10% более плотным и менее подробным, и единственным недостатком является то, что у вас будут большие проблемы, если вам придется использовать две такие библиотеки с одинаковым префиксом. Обратите внимание, что библиотеки X Window превосходны в этом отношении, за исключением того, что они забыли сделать это с помощью нескольких #defines: TRUE и FALSE должны были быть XTRUE и XFALSE, и это привело к конфликту пространства имен с Sybase или Oracle, которые также использовали TRUE и FALSE. с разными значениями! (ASCII 0 и 1 в случае базы данных!) Одним из особых преимуществ этого является то, что он неприглядно применяется к определениям препроцессора, тогда как система C ++ using / namespace их не обрабатывает. Приятным преимуществом этого является то, что он дает органичный переход от участия в проекте к тому, чтобы в конечном итоге стать библиотекой. В моем большом приложении все классы окон имеют префикс Win , все модули обработки сигналов Mod и так далее. Вероятность повторного использования любого из них мала, поэтому нет никакой практической пользы от превращения каждой группы в библиотеку, но через несколько секунд становится очевидным, как проект разбивается на подпроекты.

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

Например, если я ввожу using namespace std; и using namespace otherlib; и набираю просто cout (что бывает в обоих), а не std::cout (или ‘otherlib::cout’ ), вы можете использовать неправильный и получить ошибки. Гораздо эффективнее и эффективнее использовать std::cout .

Я не думаю, что это обязательно плохая практика в любых условиях, но вы должны быть осторожны при ее использовании. Если вы пишете библиотеку, вам, вероятно, следует использовать операторы разрешения области видимости с пространством имен, чтобы ваша библиотека не сталкивалась с другими библиотеками. Что касается кода уровня приложения, я не вижу в этом ничего плохого.

Для неквалифицированных импортированных идентификаторов вам понадобятся внешние инструменты поиска, такие как grep , чтобы узнать, где объявлены идентификаторы. Это затрудняет рассуждение о правильности программы.

Это зависит от того, где он находится. Если это общий заголовок, то вы уменьшаете значение пространства имен, объединяя его с глобальным пространством имен. Имейте в виду, что это может быть изящным способом создания глобальных модулей.

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

«Почему ‘using namespace std;’ считается плохой практикой в ​​C ++? «

Я говорю наоборот: почему некоторые считают набор пяти дополнительных символов громоздким?

Рассмотрим, например, написание части числового программного обеспечения. Зачем мне вообще рассматривать загрязнение своего глобального пространства имен путем сокращения общего «std :: vector» до «вектора», когда «вектор» является одним из наиболее важных понятий проблемной области?

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

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

Я согласен с другими — он требует противоречий в именах, двусмысленности, а на самом деле он менее явный. Хотя я вижу использование using , я лично предпочитаю ограничить его. Я бы также серьезно подумал о том, что указали некоторые другие:

Если вы хотите найти имя функции, которое может быть довольно распространенным именем, но вы хотите найти его только в пространстве имен std (или наоборот — вы хотите изменить все вызовы, которые не в пространстве имен std , пространстве имен X , . ), тогда как вы предлагаете это сделать?

Вы могли бы написать программу для этого, но не лучше ли потратить время на работу над самим проектом, а не на написание программы для поддержки вашего проекта?

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

Есть еще одна вещь, хотя она в некоторой степени связана с вышеизложенным и на то, что указывают другие. Хотя это может быть плохой практикой, я иногда резервирую std::name для стандартной версии библиотеки и имени для конкретной реализации программы. Да, действительно, это может вас укусить и сильно укусить, но все сводится к тому, что я начал этот проект с нуля, и я единственный программист для него. Пример: я перегружаю std::string и называю его string . У меня есть полезные дополнения. Я сделал это отчасти из-за моей склонности C и Unix (+ Linux) к именам в нижнем регистре.

Кроме того, у вас могут быть псевдонимы пространств имен. Вот пример того, где это полезно, о чем, возможно, не упоминалось. Я использую стандарт C ++ 11 и, в частности, libstdc ++. Что ж, у него нет полной поддержки std::regex . Конечно, он компилируется, но выдает исключение в том смысле, что это ошибка программиста. Но это отсутствие реализации.

Итак, вот как я это решил. Установите регулярное выражение Boost и свяжите его. Затем я делаю следующее, чтобы, когда libstdc ++ полностью реализовал его, мне нужно было только удалить этот блок, а код остался прежним:

Я не буду спорить, плохая это идея или нет. Однако я утверждаю, что он сохраняет его чистоту для моего проекта и в то же время делает его конкретным: правда, мне нужно использовать Boost, но я использую его как в конечном итоге он будет у libstdc ++. Да, запуск собственного проекта со стандартным (. ) в самом начале имеет очень большое значение для поддержки, разработки и всего, что связано с проектом!

Просто чтобы кое-что прояснить: я вообще-то не думаю, что использовать имя класса / чего угодно в STL намеренно и более конкретно вместо. Строка является для меня исключением (игнорируйте первое, приведенное выше или второе здесь, каламбур, если необходимо), поскольку мне не понравилась идея «Строка».

Как бы то ни было, я по-прежнему очень предвзято отношусь к C и предвзято против C ++. Забота о деталях, многое из того, над чем я работаю, больше подходит для C (но это было хорошее упражнение и хороший способ заставить себя а. Выучить другой язык и б. Попытаться не быть менее предвзятым по отношению к объектам / классам / и т. Д., Что, возможно, лучше сформулировано менее замкнутым, менее высокомерным и более принимающим). Но что полезно, так это то, что некоторые уже предлагали: я действительно использую список (он довольно общий, не так ли?) И sort (то же самое), чтобы назвать два, которые могут вызвать конфликт имен, если Я должен был сделать using namespace std; , поэтому с этой целью я предпочитаю быть конкретным, контролирующим и зная, что если я намерен использовать его в качестве стандартного, то мне придется это указать. Проще говоря: никаких предположений не допускается.

А что касается включения регулярного выражения Boost в std . Я делаю это для будущей интеграции и — опять же, я полностью признаю, что это предвзятость — я не думаю, что это так уродливо, как boost::regex:: . . На самом деле для меня это другое дело. В C ++ есть много вещей, которые мне еще предстоит полностью принять во взглядах и методах (другой пример: вариативные шаблоны против аргументов var [хотя я признаю, что вариативные шаблоны очень и очень полезны!]). Даже те, с которыми я согласен, были трудными, и у меня все еще есть проблемы с ними.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *