c++ using namespace - Почему «использование пространства имен std» считается плохой практикой?





15 Answers

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

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

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

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

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

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

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

зачем что это

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

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




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

using namespace std;
using namespace boost;

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

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




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

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 ...), потому что она короче и имеет возможность работать с определенными пользователем типами с плавающей запятой (через зависимый от аргумента поиск).




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

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




Я согласен с тем, что его нельзя использовать глобально, но не так зло использовать локально, как в 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 namespace Her_lib ( using namespace Her_lib ).




Я также считаю это плохой практикой. Зачем? Только однажды я подумал, что функция пространства имен - это разделить материал, чтобы я не портил его, выбросив все в одну глобальную сумку. Однако, если я часто использую «cout» и «cin», я пишу: using std::cout; using std::cin; using std::cout; using std::cin; в файле cpp (никогда в файле заголовка, поскольку он распространяется с #include ). Я думаю, что никто из здравомыслящих людей никогда не cout поток cout или cin . ;)




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

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

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




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

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

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




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

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 ++ от Bjarne Stroustrup




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

#include <iostream>

using namespace std;

int count = 1;
int main() {
    cout<<count<<endl;
}



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

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

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




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

Я имею в виду, действительно ... говоря «не полагайтесь на это присутствующее», просто заставляет вас полагаться на него, не присутствуя. У вас постоянно возникают проблемы с заимствованием фрагментов кода и их постоянным ремонтом. Просто держите свой пользовательский и заимствованный материал в ограниченном объеме, как и должно быть, и быть ОЧЕНЬ щадящим с глобальными (честно глобалы должны почти всегда быть последним средством для целей «компиляции сейчас, здравомыслия позже»). По-моему, это плохой совет от вашего учителя, потому что использование std будет работать как для «cout», так и для «std :: cout», но НЕ использовать std будет работать только для «std :: cout». Вам не всегда удастся написать весь свой собственный код.

ПРИМЕЧАНИЕ. Не уделяйте слишком много внимания вопросам эффективности, пока вы не узнаете немного о том, как работают компиляторы. С небольшим опытом кодирования вам не нужно много узнавать о них, прежде чем вы поймете, насколько они могут обобщить хороший код во что-то простое. Каждый бит так же просто, как если бы вы написали все в C. Хороший код настолько сложный, насколько это необходимо.




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

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

Как упоминается на этой page :

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

И посмотрите это мнение :

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

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

Как упоминается на этой page :

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

...

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

...

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




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




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




Related