Почему "использование пространства имен std" считается плохой практикой?
Мне сказали, что другие пишут using namespace std
в коде неправильно, и что я должен использовать std::cout
а также std::cin
прямо вместо.
Почему using namespace std
считается плохой практикой? Является ли это неэффективным или это рискует объявить неоднозначные переменные (переменные, которые имеют то же имя, что и функция в std
Пространство имен)? Влияет ли это на производительность?
43 ответа
Это никак не связано с производительностью. Но учтите: вы используете две библиотеки: Foo и Bar:
using namespace foo;
using namespace bar;
Все отлично работает можно позвонить Blah()
от Фу и Quux()
из бара без проблем. Но однажды вы обновляетесь до новой версии 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
и т. д.), которые, скорее всего, появятся и в другом коде.
Если вы считаете это маловероятным: здесь был задан вопрос о переполнении стека, где в значительной степени именно это и произошло (неправильная функция вызвана из-за отсутствия std::
префикс) примерно через пол года после того, как я дал этот ответ. Вот еще один, более свежий пример такого вопроса. Так что это настоящая проблема.
Вот еще один момент данных: много, много лет назад, я также находил это раздражающим, когда надо было префиксировать все из стандартной библиотеки с помощью std::
, Затем я работал в проекте, где в начале было решено, что оба using
директивы и объявления запрещены, за исключением областей действия функций. Угадай, что? Большинству из нас потребовалось очень несколько недель, чтобы привыкнуть к написанию префикса, и спустя еще несколько недель большинство из нас даже согласилось с тем, что это фактически делает код более читабельным. Для этого есть причина: нравится ли вам короткая или длинная проза, это субъективно, но префиксы объективно добавляют ясности в код. Не только компилятору, но и вам легче понять, на какой идентификатор ссылаются.
За десять лет этот проект вырос до нескольких миллионов строк кода. Поскольку эти обсуждения возникают снова и снова, мне однажды было любопытно, как часто (разрешенная) область действия функции using
на самом деле был использован в проекте. Я нашел источники для него и нашел только одно или два десятка мест, где он использовался. Для меня это означает, что после попытки разработчики не находят std::
достаточно болезненно использовать директивы хотя бы один раз каждые 100 кОл, даже там, где это было разрешено использовать.
Итог: явное добавление префиксов ко всему не приносит никакого вреда, требует очень мало привыкания и имеет объективные преимущества. В частности, это облегчает интерпретацию кода компилятором и читателями - и это, вероятно, должно быть главной целью при написании кода.
Проблема с нанесением using namespace
в заголовочных файлах ваших классов есть то, что он заставляет любого, кто хочет использовать ваши классы (включая ваши заголовочные файлы), также "использовать" (т.е. видеть все внутри) эти другие пространства имен.
Тем не менее, вы можете свободно использовать оператор using в своих (приватных) *.cpp файлах.
Имейте в виду, что некоторые люди не согласны с моим высказыванием "не стесняйтесь", как это - потому что, хотя оператор использования в файле cpp лучше, чем в заголовке (потому что он не влияет на людей, которые включают ваш файл заголовка), они думают, что это все еще не хорошо (потому что в зависимости от кода это может усложнить реализацию класса). Эта тема часто задаваемых вопросов говорит,
Директива using существует для унаследованного кода C++ и для облегчения перехода к пространствам имен, но вам, вероятно, не следует использовать его на регулярной основе, по крайней мере, в новом коде C++.
FAQ предлагает две альтернативы:
Декларация об использовании:
using std::cout; // a using-declaration lets you use cout without qualification cout << "Values:";
Просто наберите std::
std::cout << "Values:";
Недавно я столкнулся с жалобой на Visual Studio 2010. Оказалось, что почти все исходные файлы имеют следующие две строки:
using namespace std;
using namespace boost;
Многие функции Boost входят в стандарт C++0x, а Visual Studio 2010 имеет множество функций C++0x, поэтому неожиданно эти программы не компилировались.
Поэтому избегая using namespace X;
это форма проверки будущего, способ убедиться, что изменение используемых библиотек и / или заголовочных файлов не приведет к поломке программы.
Короткая версия: не используйте глобальные объявления или директивы в заголовочных файлах. Не стесняйтесь использовать их в файлах реализации. Вот что Херб Саттер и Андрей Александреску должны сказать об этой проблеме в стандартах кодирования C++ (выделение для акцента - мое):
Резюме
Использование пространства имен для вашего удобства, а не для вас, чтобы навязывать другим: Никогда не пишите объявление использования или директиву использования перед директивой #include.
Следствие: в заголовочных файлах не пишите на уровне пространства имен, используя директивы или объявления; вместо этого явно определите пространство имен для всех имен. (Второе правило следует из первого, потому что заголовки никогда не могут знать, какие другие заголовки #include могут появиться после них.)
обсуждение
Вкратце: вы можете и должны использовать пространство имен, используя объявления и директивы свободно в ваших файлах реализации после директив #include, и вам это приятно. Несмотря на неоднократные утверждения об обратном, пространства имен, использующие объявления и директивы, не являются злом и не наносят ущерба цели пространств имен. Скорее, именно они делают пространства имен пригодными для использования.
Не следует использовать директиву using в глобальном масштабе, особенно в заголовках. Однако бывают ситуации, когда это уместно даже в заголовочном файле:
template <typename FloatType> inline
FloatType compute_something(FloatType x)
{
using namespace std; //no problem since scope is limited
return exp(x) * (sin(x) - cos(x * 2) + sin(x * 3) - cos(x * 4));
}
Это лучше, чем явная квалификация (std::sin
, std::cos
...) потому что он короче и имеет возможность работать с определенными пользователем типами с плавающей запятой (через Argument Dependent Lookup).
Не используйте это глобально
Считается "плохим" только при глобальном использовании. Так как:
- Вы загромождаете пространство имен, в котором программируете.
- Читателям будет трудно увидеть, откуда исходит конкретный идентификатор, когда вы используете много
using namespace xyz
, - То, что верно для других читателей вашего исходного кода, еще более верно для самого частого читателя: вас самих. Вернитесь через год или два и посмотрите...
- Если вы говорите только о
using namespace std
вы можете не знать обо всех вещах, которые вы захватываете - и когда вы добавляете другой#include
или перейдите на новую версию C++, в которой могут возникнуть конфликты имен, о которых вы не знали.
Вы можете использовать его локально
Идите вперед и используйте его локально (почти) свободно. Это, конечно, мешает вам повторения std::
- и повторение тоже плохо.
Идиома для его локального использования
В C++03 была идиома - шаблонный код - для реализации swap
функция для ваших классов. Было предложено, чтобы вы использовали местный using namespace std
-- или по крайней мере using std::swap
:
class Thing {
int value_;
Child child_;
public:
// ...
friend void swap(Thing &a, Thing &b);
};
void swap(Thing &a, Thing &b) {
using namespace std; // make `std::swap` available
// swap all members
swap(a.value_, b.value_); // `std::stwap(int, int)`
swap(a.child_, b.child_); // `swap(Child&,Child&)` or `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
? Это что-то особенное?
Я согласен, что он не должен использоваться глобально, но это не так плохо, чтобы использовать локально, как в namespace
, Вот пример из "языка программирования C++":
namespace My_lib {
using namespace His_lib; // everything from His_lib
using namespace Her_lib; // everything from Her_lib
using His_lib::String; // resolve potential clash in favor of His_lib
using Her_lib::Vector; // resolve potential clash in favor of Her_lib
}
В этом примере мы разрешили потенциальные конфликты имен и неясности, возникающие из-за их состава.
Имена, явно объявленные там (включая имена, объявленные с помощью объявлений-объявлений, таких как His_lib::String
) иметь приоритет над именами, доступными в другой области с помощью директивы using (using namespace Her_lib
).
Опытные программисты используют все, что решает их проблемы, и избегают всего, что создает новые проблемы, и именно по этой причине они избегают использования директив уровня заголовка-файла.
Опытные программисты также стараются избегать полной квалификации имен внутри своих исходных файлов. Небольшая причина этого заключается в том, что писать элегантный код недостаточно, когда достаточно меньшего количества кода, если нет веских причин. Основной причиной этого является отключение аргумент-зависимого поиска (ADL).
Каковы эти веские причины? Иногда программисты явно хотят отключить ADL, иногда они хотят устранить неоднозначность.
Итак, все в порядке:
- Директивы использования на уровне функций и объявления использования внутри реализаций функций
- Объявления использования на уровне исходного файла внутри исходных файлов
- (Иногда) директивы using уровня исходного файла
Я также считаю это плохой практикой. Зачем? Просто однажды я подумал, что функция пространства имен состоит в том, чтобы разделять вещи, поэтому я не должен портить их, бросая все в одну глобальную сумку. Однако, если я часто использую '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:: повсеместно труднее для чтения (больше текста и все такое).
Лошади для курсов - управляйте своей сложностью так, как вы можете и можете чувствовать себя лучше.
Конкретный пример, чтобы прояснить проблему. Представьте, что у вас есть ситуация, когда у вас есть 2 библиотеки, foo и bar, каждая со своим собственным пространством имен:
namespace foo {
void a(float) { /* does something */ }
}
namespace bar {
...
}
Теперь предположим, что вы используете foo и bar вместе в своей программе следующим образом:
using namespace foo;
using namespace bar;
void main() {
a(42);
}
На данный момент все хорошо. Когда вы запускаете свою программу, она "что-то делает". Но позже вы обновляете панель и, скажем, она изменилась, чтобы быть такой:
namespace bar {
void a(float) { /* does something completely different */ }
}
В этот момент вы получите ошибку компилятора:
using namespace foo;
using namespace bar;
void main() {
a(42); // error: call to 'a' is ambiguous, should be foo::a(42)
}
Таким образом, вам нужно будет провести некоторое обслуживание, чтобы уточнить, какое "а" вы имели в виду (т.е. foo::a
). Это, вероятно, нежелательно, но, к счастью, это довольно легко (просто добавьте foo::
перед всеми призывами к a
что компилятор помечает как неоднозначный).
Но представьте альтернативный сценарий, в котором вместо этого изменился бар, и он выглядит так:
namespace bar {
void a(int) { /* does something completely different */ }
}
На данный момент ваш звонок a(42)
внезапно связывается с bar::a
вместо foo::a
и вместо того, чтобы делать "что-то", он делает "что-то совершенно другое". Нет предупреждения компилятора или что-нибудь. Ваша программа просто тихо начинает делать что-то совершенно другое, чем раньше.
Когда вы используете пространство имен, вы рискуете подобным сценарием, поэтому людям неудобно использовать пространства имен. Чем больше вещей в пространстве имен, тем больше риск конфликта, поэтому людям может быть еще более неудобно использовать пространство имен std (из-за количества вещей в этом пространстве имен), чем другие пространства имен.
В конечном итоге это компромисс между возможностью записи и надежностью / ремонтопригодностью. Читаемость может также учитывать, но я мог видеть аргументы для этого в любом случае. Обычно я бы сказал, что надежность и ремонтопригодность важнее, но в этом случае вы будете постоянно оплачивать стоимость записи за довольно редкое влияние надежности / ремонтопригодности. "Лучший" компромисс будет определять ваш проект и ваши приоритеты.
Рассматривать
// myHeader.h
#include <sstream>
using namespace std;
// someoneElses.cpp/h
#include "myHeader.h"
class stringstream { // uh oh
};
Обратите внимание, что это простой пример, если у вас есть файлы с 20 включениями и другим импортом, у вас будет тонна зависимостей, чтобы разобраться в проблеме. Хуже всего то, что вы можете получить несвязанные ошибки в других модулях в зависимости от определений, которые конфликтуют.
Это не страшно, но вы избавите себя от головной боли, не используя ее в заголовочных файлах или глобальном пространстве имен. Вероятно, это нормально делать в очень ограниченных областях, но у меня никогда не возникало проблем с набором дополнительных 5 символов, чтобы уточнить, откуда берутся мои функции.
Вы должны уметь читать код, написанный людьми, которые придерживаются мнения, отличного от вашего стиля и лучших практик.
Если вы используете только cout, никто не запутается. Но когда у вас много пространств имен, летающих вокруг, и вы видите этот класс, и вы не совсем уверены, что он делает, явное использование пространства имен действует как своего рода комментарий. На первый взгляд вы можете увидеть: "О, это операция с файловой системой" или "Это делает сеть".
Использование множества пространств имен в одно и то же время - это, очевидно, рецепт катастрофы, но использование пространства имен JUST std
и только пространство имен std
на мой взгляд, это не так уж и важно, потому что переопределение может произойти только с помощью вашего собственного кода...
Так что просто рассматривайте их функции как зарезервированные имена, такие как "int" или "class", и все.
Люди должны перестать быть такими анальными по этому поводу. Ваш учитель был прав с самого начала. Просто используйте одно пространство имен; в этом весь смысл использования пространств имен на первом месте. Вы не должны использовать более одного одновременно. Если только это не ваше. Итак, еще раз, переопределение не произойдет.
Я согласен с остальными здесь, но хотел бы решить проблемы, связанные с читабельностью - вы можете избежать всего этого, просто используя typedefs в верхней части объявления вашего файла, функции или класса.
Я обычно использую это в своем объявлении класса, поскольку методы в классе имеют тенденцию иметь дело с подобными типами данных (членами), и typedef - это возможность назначить имя, которое имеет смысл в контексте класса. Это на самом деле способствует удобочитаемости в определениях методов класса.
//header
class File
{
typedef std::vector<std::string> Lines;
Lines ReadLines();
}
и в реализации:
//cpp
Lines File::ReadLines()
{
Lines lines;
//get them...
return lines;
}
в отличие от:
//cpp
vector<string> File::ReadLines()
{
vector<string> lines;
//get them...
return lines;
}
или же:
//cpp
std::vector<std::string> File::ReadLines()
{
std::vector<std::string> lines;
//get them...
return lines;
}
Пространство имен - это именованная область. Пространства имен используются для группировки связанных объявлений и для разделения отдельных элементов. Например, две отдельно разработанные библиотеки могут использовать одно и то же имя для ссылки на разные элементы, но пользователь все равно может использовать оба:
namespace Mylib{
template<class T> class Stack{ /* ... */ };
/ / ...
}
namespace Yourlib{
class Stack{ /* ... */ };
/ / ...
}
void f(int max) {
Mylib: :Stack<int> s1(max) ; / / use my stack
Yourlib: :Stack s2(max) ; / / use your stack
/ / ...
}
Повторение имени пространства имен может отвлекать как читателей, так и писателей. Следовательно, можно утверждать, что имена из определенного пространства имен доступны без явной квалификации. Например:
void f(int max) {
using namespace Mylib; / / make names from Mylib accessible
Stack<int> s1(max) ; / / use my stack
Yourlib: :Stack s2(max) ; / / use your stack
/ / ...
}
Пространства имен предоставляют мощный инструмент для управления различными библиотеками и различными версиями кода. В частности, они предлагают программисту альтернативы того, как явно сделать ссылку на нелокальное имя.
Источник: Обзор языка программирования C++, Бьярн Страуструп
Пример, в котором при использовании пространства имен std возникает ошибка компиляции из-за неоднозначности count, которая также является функцией в библиотеке алгоритмов.
#include <iostream>
using namespace std;
int count = 1;
int main() {
cout<<count<<endl;
}
Это от случая к случаю. Мы хотим минимизировать "общую стоимость владения" программного обеспечения на протяжении его срока службы. Заявив " с помощью патезрасе" имеет некоторые издержки, но не использовать его также имеет стоимость в разборчивости.
Люди правильно отмечают, что при его использовании, когда стандартная библиотека вводит новые символы и определения, ваш код перестает компилироваться, и вы можете быть вынуждены переименовать переменные. И все же это, вероятно, хороший долгий срок, так как будущие сопровождающие на мгновение будут сбиты с толку или отвлечены, если вы используете ключевое слово для какой-то неожиданной цели.
Вы не хотите, чтобы у вас был шаблон с именем, скажем, вектор, который не известен всем остальным. И количество новых определений, введенных таким образом в библиотеку 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 и так далее. Вероятность повторного использования любого из них мала, поэтому нет никакой практической пользы от превращения каждой группы в библиотеку, но через несколько секунд становится очевидным, как проект разбивается на подпроекты.
Это не ухудшает производительность вашего программного обеспечения или проекта, включение пространства имен в начале вашего исходного кода неплохо. Включение using namespace std
инструкция варьируется в зависимости от ваших потребностей и способа разработки программного обеспечения или проекта.
namespace std
содержит стандартные функции и переменные C++ Это пространство имен полезно, когда вы часто используете стандартные функции C++.
Как упоминается на этой странице:
Утверждение, использующее пространство имен std, обычно считается плохой практикой. Альтернативой этому выражению является указание пространства имен, к которому принадлежит идентификатор, с помощью оператора области действия (::) каждый раз, когда мы объявляем тип.
И увидеть это мнение:
Нет проблем с использованием "use namespace std" в вашем исходном файле, когда вы интенсивно используете пространство имен и точно знаете, что ничего не будет конфликтовать.
Некоторые люди говорили, что включать в using namespace std
в ваших исходных файлах, потому что вы вызываете из этого пространства имен все функции и переменные. Если вы хотите определить новую функцию с тем же именем, что и другая функция, содержащаяся в namespace std
Вы перегружаете функцию, и она может вызвать проблемы из-за компиляции или выполнения. Он не будет компилироваться или выполняться так, как вы ожидаете.
Как упоминается на этой странице:
Хотя этот оператор избавляет нас от ввода std:: всякий раз, когда мы хотим получить доступ к классу или типу, определенному в пространстве имен std, он импортирует все пространство имен std в текущее пространство имен программы. Давайте возьмем несколько примеров, чтобы понять, почему это не так хорошо
...
Теперь, на более позднем этапе разработки, мы хотим использовать другую версию cout, которая реализована в некоторой библиотеке под названием "foo" (например).
...
Обратите внимание на неопределенность, на какую библиотеку указывает cout? Компилятор может обнаружить это и не скомпилировать программу. В худшем случае программа все равно может скомпилироваться, но вызвать неправильную функцию, поскольку мы никогда не указывали, к какому пространству имен принадлежит идентификатор.
Я не думаю, что это обязательно плохая практика при любых условиях, но вы должны быть осторожны, когда используете ее. Если вы пишете библиотеку, вам, вероятно, следует использовать операторы разрешения области действия с пространством имен, чтобы ваша библиотека не сталкивалась с другими библиотеками. Что касается кода уровня приложения, я не вижу в этом ничего плохого.
Из моего опыта, если у вас есть несколько библиотек, которые используют, скажем, cout
, но для другой цели вы можете использовать неправильный cout
,
Например, если я наберу, using namespace std;
а также using namespace otherlib;
и наберите просто cout (что происходит в обоих), а не std::cout
(или же 'otherlib::cout'
), вы можете использовать неправильный и получать ошибки, это гораздо более эффективно и результативно использовать std::cout
,
Я согласен с другими - это требует столкновения имен, двусмысленности, а затем факт менее явный. Хотя я могу видеть использование using
Моё личное предпочтение - ограничить это. Я также настоятельно рассмотрел бы то, на что указали некоторые другие:
Если вы хотите найти имя функции, которое может быть довольно распространенным, но вы хотите найти его только в std
пространство имен (или наоборот - вы хотите изменить все вызовы, которые НЕ находятся в пространстве имен std
, пространство имен X
,...) тогда как вы предлагаете это сделать? Вы могли бы написать программу для этого, но не лучше ли потратить время на работу над самим проектом, чем на написание программы для поддержки вашего проекта?
Лично я на самом деле не против std::
префикс. Мне больше нравится внешний вид, чем отсутствие его. Я не знаю, так ли это, потому что это явно и говорит мне: "Это не мой код... Я использую стандартную библиотеку" или это что-то еще, но я думаю, что это выглядит лучше. Это может быть странно, учитывая, что я только недавно вошел в C++ (использовал и все еще использую C и другие языки гораздо дольше, и C - мой любимый язык всех времен, прямо над сборкой).
Есть еще одна вещь, хотя она в некоторой степени связана с вышеизложенным и тем, на что указывают другие. Хотя это может быть плохой практикой, я иногда оставляю за собой std::name
для стандартной версии библиотеки и имени для конкретной реализации программы. Да, действительно, это может укусить вас и укусить вас сильно, но все сводится к тому, что я начал этот проект с нуля, и я единственный программист для него. Пример: я перегружаю std::string
и назовите это string
, У меня есть полезные дополнения. Я сделал это частично из-за моей склонности C и Unix (+ Linux) к строчным именам.
Кроме того, вы можете иметь псевдонимы пространства имен. Вот пример того, где это полезно, на которое, возможно, не ссылались. Я использую стандарт C++11 и специально с libstdC++. Ну, это не полный std::regex
служба поддержки. Конечно, он компилируется, но он выдает исключение, так как это ошибка программиста. Но это недостаток реализации. Вот как я это решил. Установите регулярное выражение Boost, свяжите его. Затем я делаю следующее, чтобы, когда libstdC++ полностью его реализовал, мне нужно было только удалить этот блок, а код остался прежним:
namespace std
{
using boost::regex;
using boost::regex_error;
using boost::regex_replace;
using boost::regex_search;
using boost::regex_match;
using boost::smatch;
namespace regex_constants = boost::regex_constants;
}
Я не буду спорить о том, что это плохая идея или нет. Я, однако, буду утверждать, что он сохраняет его чистым для МОЕГО проекта и в то же время делает его конкретным: True, я должен использовать Boost, НО я использую его так, как в итоге у libstdC++. Да, начинать собственный проект и начинать со стандартного (...) в самом начале очень долгий путь, помогая сопровождению, развитию и всему, что связано с проектом!
Редактировать:
Теперь у меня есть время, чтобы кое-что прояснить. На самом деле я не думаю, что было бы хорошей идеей использовать имя класса / что-либо в STL намеренно и более конкретно вместо. Строка является исключением (игнорируйте первое, выше или второе здесь, каламбур, если нужно) для меня, так как мне не понравилась идея "String". На самом деле, я все еще очень склонен к C и склонен к C++. Щадящие детали, большая часть того, над чем я работаю, больше подходит для C (но это было хорошее упражнение и хороший способ заставить себя а. Выучить другой язык и б. Постараться не быть менее предвзятым по отношению к объекту / классам / и т.д., что, возможно, лучше сформулировано как менее закрытый, менее высокомерный, более принимающий.) Но то, что полезно, это то, что некоторые уже предложили: я действительно использую список (это довольно универсально, не так ли?), Сортирую (то же самое), чтобы назвать два, что вызвало бы конфликт имен, если бы я сделал using namespace std;
и поэтому для этого я предпочитаю быть конкретным, контролировать и знать, что, если я намерен использовать его как стандартное использование, мне придется его указать. Проще говоря: не предполагая, допускается.
А что касается того, чтобы сделать регулярное выражение Boost частью std
, Я делаю это для будущей интеграции и - опять же, я полностью признаю, что это предвзятость - я не думаю, что это так уродливо, как boost::regex:: ...
На самом деле это другая вещь для меня. В C++ есть много вещей, которые мне еще предстоит полностью принять во взглядах и методах (еще один пример: шаблоны с переменными числами и аргументы с переменными аргументами [хотя я допускаю, что шаблоны с переменными числами очень и очень полезны!]). Даже те, которые я принимаю, были трудными, и у меня все еще есть проблемы с ними.
"Почему 'использование пространства имен std;' считается плохой практикой в C++?"
Я бы сказал иначе: почему ввод 5 дополнительных символов для некоторых считается громоздким?
Например, подумайте о написании части числового программного обеспечения. Почему бы мне даже подумать о загрязнении моего глобального пространства имен, сократив общий "std::vector" до "vector", когда "вектор" является одним из наиболее важных понятий проблемной области?
С неквалифицированными импортированными идентификаторами вам нужны внешние инструменты поиска, такие как grep, чтобы узнать, где идентификаторы объявлены. Это усложняет рассуждения о правильности программы.
Это плохая практика, часто называемая глобальным загрязнением пространства имен. Проблемы могут возникать, когда более чем одно пространство имен имеет одно и то же имя функции с сигнатурой, тогда компилятору будет неоднозначно решать, какой из них вызывать, и всего этого можно избежать, когда вы задаете пространство имен с помощью вызова функции, например std::cout
, Надеюсь это поможет.:)
Это зависит от того, где он находится. Если это общий заголовок, то вы уменьшаете значение пространства имен, объединяя его с глобальным пространством имен. Имейте в виду, это может быть аккуратный способ создания глобальных модулей.