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


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

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


2013


источник


Ответы:


Это вообще не связано с производительностью. Но учтите следующее: вы используете две библиотеки под названием Foo и Bar:

using namespace foo;
using namespace bar;

Все работает нормально, вы можете позвонить Blah()от Foo и Quux()от Бар без проблем. Но однажды вы переходите к новой версии Foo 2.0, которая теперь предлагает функцию, называемую Quux(), Теперь у вас есть конфликт: оба Foo 2.0 и Bar import Quux()в ваше глобальное пространство имен. Это потребует определенных усилий для исправления, особенно если параметры функции совпадают.

Если вы использовали foo::Blah()а также bar::Quux(), то введение foo::Quux()было бы не-событием.


1706



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

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

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

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


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

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


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


1124



Я думаю, что это плохо, чтобы поместить его в заголовочные файлы ваших классов: потому что тогда вы вынуждаете всех, кто хочет использовать ваши классы (включая ваши файлы заголовков), также «использовать» (т. Е. Видеть все) в этих других пространствах имен ,

Тем не менее, вы можете свободно указывать оператор using в своих (частных) * .cpp-файлах.


Остерегайтесь того, что некоторые люди не согласны с моим высказыванием «не стесняйтесь», как это, потому что хотя инструкция using в файле cpp лучше чем в заголовке (потому что это не влияет на людей, которые включают ваш файл заголовка), они думают, что это все еще не хорошо (потому что в зависимости от кода он мог бы затруднить выполнение этого класса). Эта тема часто задаваемых вопросов говорит,

Директива using существует для устаревшего кода на C ++ и облегчает переход к пространствам имен, но вы, вероятно, не должны использовать его на регулярной основе, по крайней мере, не в своем новом коде на C ++.

Он предлагает две альтернативы:

  • Использование объявления:

    using std::cout; // a using-declaration lets you use cout without qualification
    cout << "Values:";
    
  • Переберите его и просто введите std ::

    std::cout << "Values:";
    

304



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

using namespace std;
using namespace boost;

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

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


190



Короткая версия: не используйте глобальное использование объявлений или директив в файлах заголовков. Не стесняйтесь использовать их в файлах реализации. Вот что должны сказать Герб Саттер и Андрей Александреску об этой проблеме в Стандарты кодирования C ++ (смещение для акцента мое):

Резюме

Имена пространства имен предназначены для вашего удобства, а не для других: никогда не записывайте декларацию использования или директиву использования перед директивой #include.

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

обсуждение

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


151



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

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


97



Не используйте его во всем мире

Это считается «плохим» только тогда, когда используется в глобальном масштабе , Потому как:

  • Вы загромождаете пространство имен, в которое вы программируете.
  • У читателей будет трудность видеть, откуда приходит определенный идентификатор, когда вы используете много 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был изменен, чтобы найти потенциальную перегрузку и выбрать ее.


75



If you import the right header files you suddenly have names like hex, left, plus or count in your global scope. This might be surprising if you are not aware that std:: contains these names. If you also try to use these names locally it can lead to quite some confusion.

If all the standard stuff is in its own namespace you don't have to worry about name collisions with your code or other libraries.


68



I agree that it should not be used globally, but it's not so evil to to use locally, like in a namespace. Here's an example from "The C++ Programming Language" :

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

}

In this example, we resolved potential name clashes and ambiguities arising from their composition.

Names explicitly declared there (including names declared by using-declarations like His_lib::String) take priority over names made accessible in another scope by a using-directive (using namespace Her_lib).


30



Experienced programmers use whatever solves their problems and avoid whatever creates new problems, and they avoid header-file-level using-directives for this exact reason.

Experienced programmers also try to avoid full qualification of names inside their source files. A minor reason for this is that it's not elegant to write more code when less code is sufficient unless there are good reasons. A major reason for this is turning off argument-dependent lookup (ADL).

What are these good reasons? Sometimes programmers explicitly want to turn off ADL, other times they want to disambiguate.

So the following are OK:

  1. Function-level using-directives and using-declarations inside functions' implementations
  2. Source-file-level using-declarations inside source files
  3. (Sometimes) source-file-level using-directives

30