Немножко о using namespace std: почему ругают и чем плохо

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

У всех, наверное, студентов, начавших изучать C++, в первые же дни возникает вопрос об этом странном using namespace std: что это такое, почему одни пишут так, а другие вот так?

  • namespace — это пространство имён

C++ — это такой язык программирования, в котором очень широко используют различные подключаемые файлы. Даже чтобы просто вывести текст на экран, люди подключают, например, или файл iostream, или cstdio (наследие языка Си). В таких файлах широко применяются глобальные сущности. Одним файлом всё не ограничивается, подключают файлы очень часто, а написаны эти файлы очень разными программистами, которые даже друг о друге часто не знают. Так как они не знают друг о друге и не связаны друг с другом никакими отношениями, то и в кодах их могут оказаться одноимённые сущности.

Пётр и Вася написали два каких-то кода, в которых оказались два одноимённых класса.

Файл FilePetr.h

Файл FileWasa.h

Основная программа

Чтобы это написать, нужно знать, как писать программы, разделённые на файлы.
Если написать показанную программу и попробовать её запустить, то будет неудача, этот пример не компилируется. Возникает проблема: повторение имени. Нельзя давать одинаковые имена разным сущностям. Директива #include — это указание компилятору вписать текст из указанного файла в текущее место кода. Формально выполняется обычная подстановка текстов обоих файлов в основную программу. Происходит разворачивание в один кусок текста:

Код основной программы при компилировании выглядит вот так:

MyClass объявлен дважды, что и порождает проблему.
Самый очевидный выход борьбы с таким проявлением недоразумения — давать очень длинные имена названиям, используя всевозможные приставки, суффиксы и что-нибудь ещё. Есть только маленькое но — применение такого способа громоздит код.

В С++ возможно избежать такой проблемы достаточно простым способом. Можно создать что-то наподобие срезов глобальной области. Эти срезы с одной стороны относятся к глобальной области, с другой стороны глобальными областями не являются. Можно сказать, что глобальное пространство разбивается на границы. Получаются глобальные участки. Я надеюсь, что вы поняли то, о чём я успел написать. Дальше идёт вторая ступенька этой темы.

Файл FilePetr.h

Файл FileWasa.h

Основная программа

Если написать эту программу и запустить, то всё пройдёт гладко.
Таким образом решают проблему конфликтов в именовании. Это и есть то, откуда берёт своё начало namespace std; Теперь свободно можно использовать область видимости:
Основная программа

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

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

Именно по этой причине использование формы using namespace std; так сильно прессуется опытными программистами. Ведь программист, который пишет другой код, не обязан знать обо всём, что написано в пространстве имён std или в файлах Петра и Васи. Теперь, полагаю, читателю легче понять, что существует большой риск повторения имён.

Даже вот в таком виде, проблема остаётся:

Именно поэтому чаще всего всё сводится к узкой локализации в конкретном, в нужном месте:

Вот такая банальная причина нужна, чтобы протестовать против общеупотребимой новичками формы. Да, это быстро, удобно писать, код читабельней выглядит, но в то же время такая манера "жадного" написания кода даёт эффект описанной ошибки.

Если кода изначально написано много, а в нём использован "жадный способ" то при добавлении ещё одного файла к проекту дописывать для каждого места то, что изначально было опущено, может оказаться не самым приятным делом. Сам я не программист, поэтому не имел с этим практики, но последняя мысль моя вряд ли далека от истинны. Хотя, конечно, может я ошибся в таком выводе. Речь немного о другом: чтобы избежать случайного включения какого-либо объявления, лучше использовать прямые описания.

Жадный способ — это способ, который употребим новичками: using namespace std;
Жадным назван только мной, потому что буквально он и есть жадный: когда глобальная сущность поделена на кусочки, этот способ норовит взять всю глобальную сущность: «и для кого резали?» — спрашивается.
Это несуществующий сейчас термин, моего авторства, не специалистов.

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

Ещё одна причина некоторой нелюбви к непрямому указанию пространства имени — это возможное перекрытие переменной.

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

Здесь кода мало и программа маленькая, поэтому и исправить всё это очень легко, нужно использовать прямое обращение к глобальному пространству.
Вот пример более полного кода на самостоятельный разбор. Лучше этот код разбирать комментируя участки кода в main. Я поделил эти участки на группы по три строки, один такой блок закомментировал.

Это пример показывает не только почему использование не самого прямого пространства имён плохо/ненадёжно, но и вообще вскрывает некоторую проблему глобальных имён. Использование пространств имён с явным прописыванием способствует написанию кода без особых головных болей. Как видно в примере, даже для глобальной переменной иногда имеет смысл использовать явное указание пространства имён, в функции foo() строка кода закомментирована, где конфликт имён. Как этот пример представить проще, я не придумал, поэтому смотрите на его работу, комментируя блоки в main, и вникая в происходящее.

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

Все комментарии на сайте проверяются, поэтому ваш комментарий может появиться не сразу. Для вставки кода в комментарий используйте теги: [php]ВАШ_КОД[/php]

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

Ваш e-mail не будет опубликован.

Поиск

 
     
Яндекс.Метрика

НАГРАДИ АВТОРА САЙТА
WEBMONEY
R375024497470
U251140483387
Z301246203264
E149319127674

Работа программиста и шамана имеет много общего - оба бормочут непонятные слова, совершают непонятные действия, и не могут объяснить, как оно работает

Выражаю свою признательность

  • Максиму очень признателен за указание на мои ошибки и неточности.
  • Sergio ===> за оказание помощи в исправлении моих ошибок
  • Gen ===> за правильное стремление помочь другим новичкам и выявления моих ошибок