Если вы часто используете Стандартную библиотеку C++, то постоянное добавление std::
к используемым объектам может быть несколько утомительным, не правда ли? Язык C++ предоставляет альтернативы в виде using-стейтментов.
Использование «using-объявления»
Одной из альтернатив является использование «using-объявления». Вот программа «Hello, world!» с «using-объявлением» в строке №5:
1 2 3 4 5 6 7 8 |
#include <iostream> int main() { using std::cout; // "using-объявление" сообщает компилятору, что cout следует обрабатывать, как std::cout cout << "Hello, world!"; // и никакого префикса std:: уже здесь не нужно! return 0; } |
Строка using std::cout;
сообщает компилятору, что мы будем использовать объект cout из пространства имен std. И каждый раз, когда компилятор будет сталкиваться с cout
, он будет понимать, что это std::cout
.
Конечно, в этом случае мы не сэкономили много усилий, но в программе, где объекты из пространства имен std используются сотни, если не тысячи раз, «using-объявление» неплохо так экономит время, усилия и улучшает читабельность кода. Также для каждого объекта нужно использовать отдельное «using-объявление» (например, отдельное для std::cout
, отдельное для std::cin
и отдельное для std::endl
).
Хотя этот способ является менее предпочтительным, чем использование префикса std::
, он все же является абсолютно безопасным и приемлемым.
Использование «using-директивы»
Второй альтернативой является использование «using-директивы». Вот программа «Hello, world!» с «using-директивой» в строке №5:
1 2 3 4 5 6 7 8 |
#include <iostream> int main() { using namespace std; // "using-директива" сообщает компилятору, что мы используем все объекты из пространства имен std! cout << "Hello, world!"; // так что никакого префикса std:: здесь уже не нужно! return 0; } |
Много разработчиков спорят насчет использования «using-директивы». Так как с её помощью мы подключаем ВСЕ имена из пространства имен std, то вероятность возникновения конфликтов имен значительно возрастает (но все же эта вероятность в глобальном масштабе остается незначительной). using namespace std;
сообщает компилятору, что мы хотим использовать всё, что находится в пространстве имен std, так что, если компилятор найдет имя, которое не сможет распознать, он будет проверять его наличие в пространстве имен std.
Совет: Старайтесь избегать использования «using-директивы» (насколько это возможно).
Пример конфликта c «using-директивой»
Рассмотрим пример, где использование «using-директивы» создает неопределенность:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <iostream> int cout() // объявляем нашу собственную функцию "cout" { return 4; } int main() { using namespace std; // делаем std::cout доступным по "cout" cout << "Hello, world!"; // какой cout компилятор здесь должен использовать? Тот, который из пространства имен std или тот, который мы определили выше? return 0; } |
Здесь компилятор не сможет понять, использовать ли ему std::cout или функцию cout(), которую мы определили сами. В результате, получим ошибку неоднозначности. Хоть это и банальный пример, но если бы мы добавили префикс std::
к cout:
1 |
std::cout << "Hello, world!"; // сообщаем компилятору, что хотим использовать std::cout |
Или использовали бы «using-объявление» вместо «using-директивы»:
1 2 |
using std::cout; // сообщаем компилятору, что cout означает std::cout cout << "Hello, world!"; // так что здесь следует использовать std::cout |
Тогда наша программа была бы без ошибок.
Большинство программистов избегают использования «using-директивы» именно по этой причине. Другие считают это приемлемым до тех пор, пока «using-директива» используется только в пределах отдельных функций (что значительно сокращает масштабы возникновения конфликтов имен).
Области видимости «using-объявления» и «using-директивы»
Если «using-объявление» или «using-директива» используются в блоке, то они применяются только внутри этого блока (по обычным правилам локальной области видимости). Это хорошо, поскольку уменьшает масштабы возникновения конфликтов имен до отдельных блоков. Однако многие начинающие программисты пишут «using-директиву» в глобальной области видимости (вне функции main() или вообще вне любых функций). Этим они вытаскивают все имена из пространства имен std напрямую в глобальную область видимости, значительно увеличивая вероятность возникновения конфликтов имен. А это уже не хорошо.
Правило: Никогда не используйте using-стейтменты вне тела функций.
Отмена/замена using-стейтментов
Как только один using-стейтмент был объявлен, его невозможно отменить или заменить другим using-стейтментом в пределах области видимости, в которой он был объявлен. Например:
1 2 3 4 5 6 7 8 9 |
int main() { using namespace Boo; // Отменить «использование пространства имен Boo» здесь невозможно! // Также нет никакого способа заменить «using namespace Boo» на другой using-стейтмент return 0; } // действие using namespace Boo заканчивается здесь |
Лучшее, что вы можете сделать — это намеренно ограничить область применения using-стейтментов с самого начала, используя правила локальной области видимости:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
int main() { { using namespace Boo; // Здесь всё относится к пространству имен Boo:: } // действие using namespace Boo заканчивается здесь { using namespace Foo; // Здесь всё относится к пространству имен Foo:: } // действие using namespace Foo заканчивается здесь return 0; } |
Конечно, всей этой головной боли можно было бы избежать, просто использовав оператор разрешения области видимости (::
).
Здравствуйте. Можете подсказать список всех объектов std?
Это было бы полезно держать "под боком" во время написания программы, да и поможет запомнить наиболее часто используемые объекты.
Заранее спасибо.
http://cplusplus.com/reference/
Вот с первого урока в комментариях пишут, что надо использовать стандартное пространство имен и из-за этого комментария повылазило множество ошибок., т.к. глобальное определение вытаскивает все имена о которых учащийся даже не знает. Предлагаю кратко в начале ООП прописать или паттерны что ли, как надо делать, писать структуру кода, с чего можно начинать, а с чего нельзя начинать.
Артем, поддерживаю — дело говоришь!
Не понимаю, почему такой большой проблемой является использование using. Программисты должны знать, по идее, с какими словами будут возникать ошибки (мне, например, и в голову не придет назвать функцию или переменную cout или cin + когда мы пишем исходный код, если вдруг кому и придет идея назвать переменную cout, то программа покажет, что такое слово есть в библиотеке std). Только даун, уж извините, ошибется в таком моменте. При этом использование using экономит много времени. Не нужно постоянно прописывать имя библиотеки и ::
Я искренне за Вас рад, если Вы помните ВСЕ имена из std…
иногда возникают очень неожиданные ошибки при переходе на другой компилятор: у Вас все может работать превосходно, а на другой системе не компилироваться вообще
в примерах речь об пространстве std, но на практике может идти речь о подключении пространств имен других программистов… Вы и эти все имена запоминать планируете? Или будете вводить различные правила по использованию различных пространств имен?
Проблема в том, мой друг Горацио, что принимаются новые стандарты языка. Может быть на сегодняшний день ты выучил все имена из стандартной библиотеки и написал суперский код, настолько популярный, что его подрубают как библиотеку во все серверные приложения. Но вот принимается новый стандарт и в этот злосчастный std могут запихивают новое имя, которое вызывает конфликт с твоим. Угадай, к кому будут вопросы после того, как либа перестанет работать?