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

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

  • автор:

Пространства имен (C++)

Пространство имен — это декларативная область, в рамках которой определяются различные идентификаторы (имена типов, функций, переменных, и т. д.). Пространства имен используются для организации кода в виде логических групп и с целью избежания конфликтов имен, которые могут возникнуть, особенно в таких случаях, когда база кода включает несколько библиотек. Все идентификаторы в пределах пространства имен доступны друг другу без уточнения. Идентификаторы за пределами пространства имен могут получить доступ к членам с помощью полного имени для каждого идентификатора, например, с помощью объявления для одного идентификатора ( using std::string ) или директивы using для всех идентификаторов в пространстве имен ( using namespace std; ). std::vector vec; Код в файлах заголовков всегда должен содержать полное имя в пространстве имен.

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

namespace ContosoData < class ObjectManager < public: void DoSomething() <>>; void Func(ObjectManager) <> > 

Использование полного имени:

ContosoData::ObjectManager mgr; mgr.DoSomething(); ContosoData::Func(mgr); 

Чтобы добавить в область видимости один идентификатор, используйте объявление using:

using ContosoData::ObjectManager; ObjectManager mgr; mgr.DoSomething(); 

Чтобы добавить в область видимости все идентификаторы пространства имен, используйте директиву using:

using namespace ContosoData; ObjectManager mgr; mgr.DoSomething(); Func(mgr); 

Директивы using

Директива using позволяет использовать все имена в объекте namespace без имени пространства имен в качестве явного квалификатора. Используйте директиву using в файле реализации (т. е. *.cpp), если используется несколько различных идентификаторов в пространстве имен; Если вы используете только один или два идентификатора, рассмотрите возможность использования объявления, чтобы использовать только эти идентификаторы в область, а не все идентификаторы в пространстве имен. Если локальная переменная имеет такое же имя, как и переменная пространства имен, то переменная пространства имен будет скрытой. Создавать переменную пространства имен с те же именем, что и у глобальной переменной, является ошибкой.

Директиву using можно поместить в верхнюю часть CPP-файла (в области видимости файла) или внутрь определения класса или функции.

Без особой необходимости не размещайте директивы using в файлах заголовков (*.h), так как любой файл, содержащий этот заголовок, добавит все идентификаторы пространства имен в область видимости, что может вызвать скрытие или конфликты имен, которые очень трудно отлаживать. В файлах заголовков всегда используйте полные имена. Если эти имена получаются слишком длинными, используйте псевдоним пространства имен для их сокращения. (См. ниже.)

Объявление пространств имен и их членов

Как правило, пространство имен объявляется в файле заголовка. Если реализации функций находятся в отдельном файле, определяйте имена функций полностью, как показано в следующем примере.

// contosoData.h #pragma once namespace ContosoDataServer

Реализации функций в contosodata.cpp должны использовать полное имя, даже если директива using размещается в верхней части файла:

#include "contosodata.h" using namespace ContosoDataServer; void ContosoDataServer::Foo() // use fully-qualified name here < // no qualification needed for Bar() Bar(); >int ContosoDataServer::Bar()

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

Члены именованного пространства имен можно определить вне пространства имен, в котором они объявлены явным определением имени. Однако определение должно располагаться после точки объявления в пространстве имен, окружающем то пространство имен, где находится объявление. Например:

// defining_namespace_members.cpp // C2039 expected namespace V < void f(); >void V::f() < >// ok void V::g() < >// C2039, g() is not yet a member of V namespace V

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

Глобальное пространство имен

Если идентификатор не объявлен явно в пространстве имен, он неявно считается входящим в глобальное пространство имен. Как правило, старайтесь избегать объявления в глобальном область, если это возможно, за исключением основной функции точки входа, которая должна находиться в глобальном пространстве имен. Чтобы явно указать глобальный идентификатор, используйте оператор разрешения области видимости без имени, как сделано в ::SomeFunction(x); . Это позволит отличать данный идентификатор от любого другого элемента с таким же именем, находящегося в другом пространстве имен. Кроме того, это облегчит понимание кода.

Пространство имен std

Все стандартные типы и функции библиотек C++ объявляются в std пространстве имен или пространствах имен, вложенных внутри std .

Вложенные пространства имен

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

namespace ContosoDataServer < void Foo(); namespace Details < int CountImpl; void Ban() < return Foo(); >> int Bar(); int Baz(int i) < return Details::CountImpl; >> 

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

Встроенные пространства имен (C++11)

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

// Header.h #include namespace Test < namespace old_ns < std::string Func() < return std::string("Hello from old"); >> inline namespace new_ns < std::string Func() < return std::string("Hello from new"); >> > // main.cpp #include "header.h" #include #include int main() < using namespace Test; using namespace std; string s = Func(); std::cout 

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

namespace Parent < inline namespace new_ns < template struct C < T member; >; > template<> class C <>; > 

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

Ключевое слово inline должно применяться к первому объявлению пространства имен в единице компиляции.

В следующем примере показано две версии интерфейса: каждое — во вложенном пространстве имен. Пространство имен v_20 содержит некоторые изменения из интерфейса v_10 и помечается как встроенное. Клиентский код, который использует новую библиотеку и вызывает Contoso::Funcs::Add , вызовет версию v_20. Код, который пытается вызвать Contoso::Funcs::Divide , теперь будет вызывать ошибку времени компиляции. Если действительно требуется эта функция, доступ к версии v_10 можно получить путем явного вызова Contoso::v_10::Funcs::Divide .

namespace Contoso < namespace v_10 < template class Funcs < public: Funcs(void); T Add(T a, T b); T Subtract(T a, T b); T Multiply(T a, T b); T Divide(T a, T b); >; > inline namespace v_20 < template class Funcs < public: Funcs(void); T Add(T a, T b); T Subtract(T a, T b); T Multiply(T a, T b); std::vectorLog(double); T Accumulate(std::vector nums); >; > > 

Псевдонимы пространств имен

Имена пространств имен должны быть уникальными, из-за чего зачастую они получаются не слишком короткими. Если длина имени затрудняет чтение кода или утомительно вводить в файл заголовка, где нельзя использовать директивы, можно сделать псевдоним пространства имен, который служит сокращенным для фактического имени. Например:

namespace a_very_long_namespace_name < class Foo <>; > namespace AVLNN = a_very_long_namespace_name; void Bar(AVLNN::Foo foo)

анонимные или безымянные пространства имен

Вы можете создать явное пространство имен, но не присвоить ему имя.

namespace < int MyFunc()<>> 

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

Почему using namespace std - плохо?

Используя пространства имен, мы можем явно указать, из какого пространства имен мы хотим использовать определенный символ. Например, в коде std::cout , std является пространством имен, а cout - символом из этого пространства имен, представляющим стандартный поток вывода. Использование ключевого слова using namespace std позволяет нам обращаться к символам из пространства имен std без явного указания этого пространства имен каждый раз. Однако, это также может привести к проблемам. Например, если мы имеем два различных пространства имен, каждое со своим символом info , и мы используем using namespace для обоих пространств имен, то возникает конфликт имён. Компилятор не знает, из какого пространства имен мы хотим использовать info , и может возникнуть неоднозначность. Чтобы избежать таких проблем, хорошей практикой является указывать пространство имен перед каждым символом или использовать только необходимые символы из пространства имен с помощью оператора разрешения области видимости :: . Также стоит избегать использования using namespace в глобальной области видимости в заголовочных файлах, чтобы не добавлять символы из пространства имен в глобальную область видимости всего проекта.

Более простым языком я рассказал об этом в своем телеграм канале: https://t.me/Aren_et_adventures/12

Категории

Счётчик посещений

Теги

© Арен Елчинян 2022-2023 Powered byBludit

Стоит ли переходить на std:: или же лучше остаться на using namespace std?

Пишу на C++. Слышал что хорошие программисты используют std:: . Стоит ли тоже перейти и писать так же или же лучше оставаться на using namespace std и не вешать геморой на задницу?

  • Вопрос задан более трёх лет назад
  • 946 просмотров

5 комментариев

Простой 5 комментариев

longclaps

По правде, это именно то, без чего тебе никогда не стать хорошим программистом.
vladik_koresh @vladik_koresh Автор вопроса
longclaps, а можешь объяснить зачем его использовать, в чём плюсы? Ведь зачем то облегчили юзингом.

longclaps

vladik_koresh, ну что ты как маленький? Какой кодестайл в команде принят, в таком и пишут.
vladik_koresh @vladik_koresh Автор вопроса
longclaps, я не опытный программист, да и вообще ещё не программист толком)

myjcom

Roman @myjcom Куратор тега C++
Решения вопроса 0
Ответы на вопрос 2

mrjbom

А какие минусы в использовании using namespace std? По моему никаких, это только делает код более читабельным.

Ответ написан более трёх лет назад
Комментировать
Нравится 1 Комментировать
Vitaly @vt4a2h Куратор тега C++
Senior software engineer (C++/Qt/boost)

Основная проблема -- это возможные конфликты имён, в особенности, если вы прописываете использование нескольких пространств имён таким образом. Помимо этого, есть риск получить очень много вариантов различных конструкций в списке автодополнения IDE. Сам по себе std -- это очень короткий идентификатор, поэтому опускать его нет особого смысла.

PS
Ко всему прочему, никогда не пишите "using namespace" в заголовочных файлах. За исключением случаев, когда вы действительно понимаете что делаете.

Ответ написан более трёх лет назад
Комментировать
Нравится 1 Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

cpp

  • C++
  • +2 ещё

Как убрать ненужное пространство между кнопками c++ Windows forms CLI?

  • 1 подписчик
  • 28 минут назад
  • 10 просмотров

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

Здравствуйте! Почему использование пространства имен std (using namespace std) считается плохой практикой? Язык плюсы изучаю сам, та и тем более мне этот язык сильно нравиться.Смотрел лекции на ютубе которые вел Тимофей Харьянов - именно он говорил что использование using namespace std это очень плохо, даже Бьёрн Страуструп не рекомендует..Пошел гуглить как ответа и не понял..

  • Вопрос задан более трёх лет назад
  • 808 просмотров

Комментировать

Решения вопроса 1

Adamos

Например, потому, что в пространстве std хренова туча объявленных в библиотеке функций, про которые вы, возможно, даже не подозреваете. И можете назвать свою собственную функцию так же. Даже не подозревая, что при каждом ее вызове компилятор теперь сомневается, которую использовать - вашу или библиотечную. И решение в пользу библиотечной (например, потому, что вы ошиблись в аргументах) окажется для вас сюрпризом.

Ответ написан более трёх лет назад

Нравится 6 4 комментария

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

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