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

2322

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

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

  • 429
    Не забудьте, что вы можете сделать: «используя std :: cout;» Это означает, что вам не нужно вводить std :: cout, но не вводить все пространство имен std одновременно.
  • 0
    @a платный ботаник google-styleguide.googlecode.com/svn/trunk/… ссылка больше не работает. Похоже, новая ссылка google.github.io/styleguide/cppguide.html#Other_C++_Features
Показать ещё 5 комментариев
Теги:
namespaces
std
using-directives
c++-faq

36 ответов

1956
Лучший ответ

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

using namespace foo;
using namespace bar;

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

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

  • 361
    Мне всегда нравился Python "import big_honkin_name as bhn", так что тогда вы можете просто использовать "bhn.something" вместо "big_honkin_name.something" - действительно сократить ввод текста. Есть ли в C ++ что-то подобное?
  • 669
    Пространство имен @Pax io = boost :: filesystem;
Показать ещё 37 комментариев
1274

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

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

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

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


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

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


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

  • 114
    Это значительно ухудшает плотность кода, который вы можете упаковать в одну строку. Вы заканчиваете тем, что пишете свой код очень многословным способом; что снижает читабельность. Лично я думаю, что более короткий (но не слишком короткий) код имеет тенденцию быть более читабельным (так как там меньше материала для чтения и меньше вещей, которые нужно отвлекать).
  • 12
    @Lie: Любите ли вы короткую или длинную прозу, это субъективное предпочтение . (Я встречал разработчиков, которым действительно нравились длинные идентификаторы, хотя это означало, что им приходилось разделять свои строки даже для самых простых вызовов функций.) Если вы точно видите, какой идентификатор, OTOH, упоминается, является объективным критерием . FWIW, я имел обыкновение делиться вашим POV , был вынужден попробовать другую сторону, и никогда не оглядывался назад.
Показать ещё 36 комментариев
321

Проблема с 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:";
    
  • 28
    Поменьше поместить его в файл .cpp, чем в заголовок, но проблема остается неизменной для удобства сопровождения. Существует риск того, что две функции с одинаковыми именами столкнутся, когда код / используемая вами библиотека / стандарт C ++ будут изменены.
  • 2
    Вы пробовали это вообще? Потому что директива using namespace не будет перенесена в другой файл. (GCC 4.8+)
Показать ещё 16 комментариев
213

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

using namespace std;
using namespace boost;

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

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

  • 8
    Это. Boost и std имеют много общего - особенно начиная с C ++ 11.
  • 0
    Я сделал это однажды и усвоил урок трудным путем. Теперь я никогда не использую using вне определения функции и редко использую using namespace вообще.
170

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

Резюме

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

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

Обсуждение

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

  • 49
    Грустно, что это вменяемое руководство так погребено под ошибочными ответами.
  • 3
    Еще одно мнение программиста, но хотя я полностью согласен с утверждением о том, что слово using никогда не должно появляться в заголовке, я не настолько убежден в том, что свободная лицензия размещается using namespace xyz; в любом месте вашего кода, особенно если xyz является std . Я использую using std::vector; форма, поскольку это тянет только один элемент из пространства имен в псевдоглобальную область, что приводит к гораздо меньшему риску столкновения.
Показать ещё 3 комментария
105

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

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

  • 7
    Извините, но я категорически не согласен с этим.
  • 3
    @Billy: нет другого способа поддержать вызов userlib :: cos (userlib :: superint). Каждая функция имеет применение.
Показать ещё 6 комментариев
90

Не используйте его глобально

Он считается "плохим", только когда используется глобально. Потому что:

  • Вы загромождаете пространство имен, в котором вы программируете.
  • У читателей будет трудность видеть, откуда приходит определенный идентификатор, когда вы используете много using namespace xyz.
  • Что бы ни было верно для других читателей вашего исходного кода, это еще более верно для самого частого читателя: самого себя. Вернитесь через год или два и посмотрите...
  • Если вы говорите только о using namespace std, вы можете не знать обо всех материалах, которые вы захватите, и когда вы добавите еще один #include или перейдете к новой версии С++, вы можете получить конфликты имен, о которых вы не знали.

Вы можете использовать его локально

Идем дальше и используем его локально (почти) свободно. Это, конечно, предотвращает повторение std:: - и повторение также плохое.

Идиома для локального использования

В С++ 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&) и попытаться наилучшим образом заменить их.

С С++ 11 нет причин использовать этот шаблон больше. Реализация std::swap была изменена, чтобы найти потенциальную перегрузку и выбрать ее.

  • 4
    «Реализация std :: swap была изменена, чтобы найти потенциальную перегрузку и выбрать ее». - Какие? Вы уверены, что? Хотя это правда, что предоставление пользовательского swap в первую очередь не так уж важно в C ++ 11, так как сам std::swap более гибок (использует семантику перемещения). Но std::swap автоматически выбирает ваш собственный своп, что для меня абсолютно ново (и я в это не верю).
  • 0
    @ChristianRau Я так думаю, да. Я читал это на SO где-то. Мы всегда можем спросить Говарда , он должен знать. Я копаю и копаю сейчас ...
Показать ещё 7 комментариев
70

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

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

  • 11
    +1 не говоря уже о distance . все же я предпочитаю неквалифицированные имена там, где это практически возможно, так как это повышает читабельность для меня. Кроме того, я думаю, что тот факт, что мы обычно не квалифицируем вещи в устной речи и готовы тратить время на устранение возможных двусмысленностей, означает, что имеет смысл уметь понимать то, о чем идет речь, без оговорок и применяться к источнику код, который означает, что он структурирован таким образом, что понятно, о чем идет речь, даже без квалификации.
  • 0
    Если честно, у вас их не будет, если вы не <iomanip> . Тем не менее, хороший момент.
38

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

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

Каковы эти веские причины? Иногда программисты явно хотят отключить ADL, в других случаях они хотят устранить неоднозначность.

Итак, все в порядке:

  • Использование-директив на уровне функций и использование-деклараций внутри реализации функций
  • Использование-объявления уровня исходного файла в исходных файлах
  • (Иногда) с использованием-директив на уровне исходного файла
  • 3
    Определите «элегантность».
36

Я согласен, что его нельзя использовать глобально, но не так зло использовать локально, как в namespace. Вот пример из "Язык программирования С++":

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).

36

Еще одна причина - сюрприз.

Если я вижу cout << blah вместо std::cout << blah

Я думаю, что это за cout? Это нормальный cout? Это что-то особенное?

  • 12
    Это шутка? Я искренне не могу сказать. Если нет, то я лично предположил бы, что это нормальное «бдение», если вы не доверяете коду, так как в противном случае это был бы ВНЕШНИЙ запах кода, ИМО. ... А если вы не доверяете коду, то почему вы используете его в первую очередь? Обратите внимание, что я не говорю "ДОВЕРЯЙТЕ ВСЕМ !!" но это также кажется немного надуманным, если вы, скажем, имеете дело с какой-то известной библиотекой из GitHub или чем-то еще.
  • 15
    @BrentRittenhouse cout - плохой пример, потому что все это признают. Но представьте себе future в финансовом приложении. Это контракт на покупку или продажу чего-либо на указанную дату? Нет, это не так. Если бы в коде говорилось о std::future вас не так легко спутать.
Показать ещё 1 комментарий
25

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

  • 6
    Это локальное объявление об использовании, совершенно отличное от использования директивы .
22

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

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

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

  • 2
    Откуда вы знаете, что std :: cout << 1 не читает статическое int с именем cout в пространстве имен std, сдвигая его на единицу и выбрасывая результат? Кроме того, как вы знаете, что "<<" делает;) ??? ... кажется, что этот ответ не является хорошей точкой данных, чтобы избежать "использования".
  • 4
    Если кто-то переопределил std :: cout как целое число, то ваша проблема не техническая, а социальная - у кого-то это есть для вас. (и вам, вероятно, следует также проверить все заголовки на наличие таких вещей, как #define true false и т. д.)
Показать ещё 1 комментарий
19

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

Лошади для курсов - управляйте своей сложностью, как вы можете и можете себя чувствовать.

17

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

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

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

  • 0
    Создание коллизий не так сложно - короткие строки, такие как min , end и less появляются в пространстве имен std:: . Более того, теперь, когда в std:: есть тысячи символов, читателю полезно знать, откуда появился новый символ, который они могут не знать.
  • 0
    Пространство имен std существует потому, что люди, вы, ваши коллеги или люди, пишущие промежуточное программное обеспечение, которое вы используете, не всегда мудры в размещении функций внутри пространств имен. Таким образом, вы можете импортировать все std :: и ничего больше, в то же время вызывая коллизию между, скажем, std :: min и чьим-либо наследием :: min () до того времени, когда он был в std.
17
  • вам нужно уметь читать код, написанный людьми, которые имеют разные мнения о стиле и лучшей практике, чем вы.

  • Если вы используете cout, никто не смущается. Но когда у вас много пространств имен, которые летают, и вы видите этот класс, и вы не совсем уверены, что он делает, поскольку явное пространство имен действует как комментарий рода. Вы можете видеть на первый взгляд: "О, это операция с файловой системой" или "Что делает сетевые вещи".

16

Рассмотрим

// myHeader.h
#include <sstream>
using namespace std;


// someoneElses.cpp/h
#include "myHeader.h"

class stringstream {  // uh oh
};

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

Это не ужасно, но вы избавитесь от головных болей, не используя его в файлах заголовков или в глобальном пространстве имен. Скорее всего, это можно сделать в очень ограниченных областях, но у меня никогда не было проблемы с вводом дополнительных 5 символов, чтобы выяснить, откуда мои функции.

11

Конкретный пример для разъяснения проблемы. Представьте, что у вас есть ситуация, когда у вас есть 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)
}

Итак, вам нужно будет провести некоторое техническое обслуживание, чтобы уточнить, что означало "a" (т.е. foo::a). Это, вероятно, нежелательно, но, к счастью, это довольно просто (просто добавьте foo:: перед всеми вызовами a, которые компилятор отмечает как неоднозначный).

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

namespace bar {
    void a(int) { /* does something completely different */ }
}

В этот момент ваш вызов a(42) внезапно привязывается к bar::a вместо foo::a и вместо того, чтобы делать что-то, он делает что-то совершенно другое. Никакого предупреждения компилятора или чего-либо еще. Ваша программа просто начинает делать что-то совершенно иное, чем раньше.

Когда вы используете пространство имен, вы рискуете подобным сценарием, поэтому людям неудобно использовать пространства имен. Чем больше вещей в пространстве имен, тем больше риск конфликта, поэтому людям может быть еще более неудобно использование пространства имен std (из-за количества вещей в этом пространстве имен), чем другие пространства имен.

В конечном счете это компромисс между возможностью записи и надежностью/ремонтопригодностью. Читаемость также может иметь значение, но я могу видеть аргументы для этого в любом случае. Обычно я бы сказал, что надежность и ремонтопригодность важнее, но в этом случае вы будете постоянно оплачивать затраты на запись для довольно редкой надежности/ремонтопригодности. "Лучший" компромисс будет определять ваш проект и ваши приоритеты.

11

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

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
    / / ...
}

Пространства имен предоставляют мощный инструмент для управления различными библиотеками и различными версиями   код. В частности, они предлагают альтернативу программиста того, как явным становится ссылка на нелокальную   имя.

Источник: обзор языка программирования С++ by Bjarne Stroustrup

  • 3
    Очень интересно, что этот ответ, основанный на рекомендациях других, что Бьярн Страуструп заработал -2 ... мальчик Бьярне, должно быть, был плохим и неопытным программистом, когда вводил эту функцию в C ++
  • 0
    @nyholku: Посмотри на это .
10

Я согласен с остальными здесь, но хотел бы затронуть проблемы, связанные с удобочитаемостью - вы можете избежать всего этого, просто используя 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;
}
  • 0
    Просто небольшой комментарий, хотя typedef полезен, я бы подумал о создании класса, представляющего строки вместо использования typedef.
9

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

#include <iostream>

using namespace std;

int count = 1;
int main() {
    cout<<count<<endl;
}
  • 1
    ::count проблема решена. Обычно из пространства имен std у вас будет больше информации, чем из других мест, поэтому сохранение директивы using namespace может спасти вам ввод текста.
  • 0
    Настоящая проблема здесь в том, что в C ++ все еще есть глобалы без пространства имен. Это и тот факт, что «this» неявно присутствует в методах, вызывает столько ошибок и проблем, что я даже не могу их сосчитать, даже с правильной переменной «count». ;)
8

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

6

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

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

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

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

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

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

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

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

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

...

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

...

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

6

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

6

Я согласен с другими - он спрашивает о столкновениях имен, двусмысленностях, а затем тот факт, что он менее явный. Хотя я вижу использование using, мое личное предпочтение - ограничить его. Я также решительно рассмотрю то, что некоторые другие отметили:

Если вы хотите найти имя функции, которое может быть довольно распространенным именем, но вы хотите только найти его в пространстве имен std (или наоборот - вы хотите изменить все вызовы, которые НЕ находятся в пространстве имен std, namespace X,...), то как вы предлагаете это сделать? Вы могли бы написать программу для этого, но не лучше ли тратить время на работу над самим проектом, а не на создание программы для поддержки вашего проекта?

Лично я на самом деле не против std:: prefix. Мне нравится выглядеть больше, чем не иметь его. Я не знаю, потому что это явное и говорит мне: "Это не мой код... я использую стандартную библиотеку", или если это что-то еще, но я думаю, что это выглядит лучше. Это может быть странно, учитывая, что я только недавно попал в C++ (используется и все еще делает C и другие языки намного дольше, а C - мой любимый язык всех времен, прямо над сборкой).

Есть еще одна вещь, хотя она несколько связана с вышесказанным и что другие указывают. Хотя это может быть плохой практикой, я иногда резервирую std::name для стандартной версии библиотеки и имени для реализации конкретной программы. Да, действительно, это может вас укусить и укусить, но все сводится к тому, что я начал этот проект с нуля, и я для него единственный программист. Пример: я перегружаю std::string и называю его string. У меня есть полезные дополнения. Я сделал это частично из-за моей тенденции C и Unix (+ Linux) к именам нижнего регистра.

Кроме того, вы можете иметь псевдонимы пространства имен. Вот пример того, где это полезно, о котором, возможно, не обращалось. Я использую стандарт C++ 11 и, в частности, с libstd C++. Ну, у него нет полной поддержки std::regex. Конечно, он компилируется, но он выдает исключение по тому, что это ошибка на конце программиста. Но это недостаток в реализации. Итак, вот как я это решил. Установите Boost regex и свяжите его. Затем я делаю следующее, чтобы, когда libstd C++ полностью реализовал его, мне нужно только удалить этот блок, а код останется тем же:

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

Редактировать:
Теперь, когда у меня есть время, просто что-то прояснить. На самом деле я не считаю целесообразным использовать имя класса/любого в STL намеренно и, более конкретно, вместо. Строка - это исключение (игнорируйте первый, выше или второй здесь, каламбур, если вы должны) для меня, поскольку мне не понравилась идея "String". Как бы то ни было, я все еще очень склонен к C и предвзято относился к C++. Сохраняя детали, многое из того, что я работаю, больше подходит для C (но это было хорошее упражнение и хороший способ сделать себя). Изучите другой язык и b. Попробуйте не быть менее предвзятым против объекта/классов /etc, который, возможно, как менее замкнутый, менее высокомерный, более приемный.). Но полезно то, что некоторые из них уже предлагали: я действительно использую список (он довольно общий, не так ли?), Сортировать (то же самое), чтобы называть два, которые вызовут столкновение имен, если я буду делать using namespace std; и поэтому с этой целью я предпочитаю быть конкретным, контролировать и знать, что, если я намереваюсь, чтобы это было стандартное использование, мне придется его указать. Проще говоря: не допускается.

А что касается создания регулярного выражения Boost std. Я делаю это для будущей интеграции, и, опять же, я полностью признаю, что это предвзятость - я не думаю, что это так же уродливо, как boost::regex::... Для меня это другое дело. В C++ есть много вещей, которые я до сих пор еще не получил, чтобы полностью согласиться на внешний вид и методы (еще один пример: вариативные шаблоны против var args [хотя я допускаю, что вариативные шаблоны очень полезны!]). Даже те, что я принимаю, это было трудно, и у меня все еще есть проблемы с ними.

6

"Почему" using namespace std; "считается плохой практикой в ​​С++?"

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

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

  • 18
    Это не просто 5 дополнительных символов; его 5 дополнительных символов каждый раз, когда вы ссылаетесь на любой тип объекта в стандартной библиотеке. Что, если вы используете стандартную библиотеку очень часто, будет часто. Таким образом, в программе приличного размера более реалистично тысячи дополнительных символов. Предположительно, в язык была добавлена директива using, чтобы ее можно было использовать ...
  • 2
    Это не 5 дополнительных символов каждый раз, это 5 символов и, возможно, пара щелчков мыши, чтобы открыть меню и выполнить поиск и замену в редакторе по вашему выбору.
Показать ещё 4 комментария
6

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

5

Из моего опыта, если у вас есть несколько библиотек, которые используют, скажем, cout, но для другой цели вы можете использовать неправильный cout.

Например, если я набираю using namespace std; и using namespace otherlib; и набираю только cout (что бывает в обоих), а не std::cout (или 'otherlib::cout'), вы можете использовать неправильный, и получить ошибки, гораздо эффективнее и эффективнее использовать std::cout.

5

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

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

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

  • 0
    Учитывая, что многие люди, кажется, не знают о полезных стандартных функциях библиотеки (например, заново изобретают что-то из <algorithm> ), кажется немного натянутой мысль, что одни и те же люди могут надежно избегать этих идентификаторов. Посмотрите свой собственный код и скажите, что у вас никогда нет переменной или функции с именем count . Или distance , или log , destroy , launch , visit , beta , sample , messages , clamp , erase , copy , modulus , left и т. Д. Не говоря уже о всех идентификаторах, которые еще не в std которые будут нарушать ваш код, когда C ++ 35 выходит...
5

С неквалифицированными импортированными идентификаторами вам нужны внешние инструменты поиска, такие как grep, чтобы узнать, где объявляются идентификаторы. Это затрудняет обоснование корректности программы.

4

Да, пространство имен важно. Однажды в моем проекте мне нужно было импортировать одно объявление var в исходный код, но при компиляции он противоречил другой сторонней библиотеке.

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

2

Вот пример, показывающий, как using namespace std; может вызвать проблемы с конфликтом имен:

Невозможно определить глобальную переменную в С++

В примере очень общее имя имени алгоритма (std::count) сталкивается с очень разумным именем переменной (count).

2

Я думаю, что использование локально или глобально должно зависеть от приложения.

Поскольку,   когда мы используем библиотеку локально, иногда код становится настоящим беспорядком. Читаемость будет низкой.

поэтому мы должны использовать библиотеки локально, только когда есть возможность конфликтов.

Я больше не переживаю человека. Итак, дайте мне знать, если я ошибаюсь.

1

Честно говоря, для меня это как обсуждение количества пробелов для отступов. Использование директив в заголовках может привести к повреждению. Но в файлах c++? Возможно, если вы используете сразу 2 пространства имен. Но если вы используете один, это больше о стиле, чем реальной эффективности. Знаете ли вы, почему темы об углублении настолько популярны? Любой может сказать что-то об этом и звучать очень умный и опытный.

1

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

Можно считать, что он имеет невидимый префикс библиотеки - std::vector становится просто vector. Это, на мой взгляд, лучшее из обоих миров: с одной стороны, это уменьшает объем ввода, который вы должны делать (как это предусмотрено пространствами имен), а с другой - для по-прежнему требуется использовать префиксы для ясности и безопасности. Если есть функция или объект без префикса пространства имен - вы знаете это из одного указанного вами пространства имен.

Просто помните, что если вы решите использовать один глобально - не используйте других локально. Это возвращается к другим ответам, что локальные пространства имен часто более полезны, чем глобальные, поскольку они обеспечивают разнообразие в удобстве.

-2

Существует несколько причин, которые включают в себя пространство имен std, как плохую практику. По существу, это сводится к следующим основным моментам:

  • Как правило, лучше писать четкий явный код, чем неявный код, поскольку он улучшает читабельность вашей программы
  • По #include пространства имен вы рискуете столкновениями имен.

    При этом, пока вы не подвергаете других использовать пространство имен, помещая их в свои файлы заголовков, а вместо этого используйте его локально, он может добавить справедливый бит убеждения, оказывая минимальное влияние на читаемость. Допустимо #include namespace std в ваших реализациях собственного класса.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню