Резолюция C++ Имя
мне интересно, немного о namespace
и using
в C++ в принципе я хотел бы знать различия и выяснить, как использовать его наилучшим образом.
как я вижу, есть (по крайней мере) три способа решить имя класса, и я не уверен, как выбрать среди них:
using namespace <namespace>
using <namespace>::<what_to_use>
<namespace>::<what_to_use> <use_it>
Я хотел бы знать преимущества, особенно если есть представление, участвующих в одном или наоборот, если это просто синтаксический и вопрос предпочтения или если есть другие вещи, которые я не рассматривал в отношении этого.
5 ответов
первое-это С помощью директивы пространства имен, он приносит все имена символов из указанного пространства имен в текущем пространстве имен, независимо от того, нужно ли вам/использовать их. Конечно, нежелательно.
второй -С помощью декларации пространства имен. Он приносит только указанное имя символа в текущем пространстве имен. Преимущество заключается в том, что вам не нужно вводить полное имя каждый раз.
третья полные имена символ. Недостатком является то, что вы должны ввести полное имя везде, где вы используете символ.
ясно, второй и третий являются более подходящими. Ни в одном из них нет разницы в производительности. Разница только в количестве вводимых символов. Просто выберите в зависимости от вашего кодирования укажет.
изменить:
Как указывает @Jerry, использование объявления в сочетании с ADL (Поиск, зависящий от аргумента) может привести к нежелательным последствиям.
Вы можете найти подробное объяснение в одном из моих ответов:
подробное объяснение того, как Koenig lookup работает с пространствами имен и почему это хорошо?
в разделе
Почему критика Кенига Алгоритм?
есть одна (по общему признанию, несколько необычная) ситуация, в которой форма, которую вы используете, действительно может иметь значение, и форма, которую вы хотите использовать is using namespace foo
, и это наиболее часто применяется к std
пространство имен (т. е., когда вы пишите using namespace std;
.
наиболее очевидным примером является то, что вы пишете сортировку для определенного пользователем типа. Это возможно это будет применено к типу, для которого пользователь также определил свой собственный swap
.
вы застряли в ситуации, когда вы хотите использовать их своп, если они определили его, но используйте std::swap, если они его не определили. Если вы используете std::swap
непосредственно в вашем коде, то вы в конечном итоге с помощью std::swap
даже если тип имеет собственный определенный своп. И наоборот, ваш код не будет компилироваться, если вы непосредственно укажете своп специально для типа, и ни один из них не был предоставлен.
чтобы обойти это, вы делаете что-то например:
using namespace std;
template <class Iter>
void my_sort(Iter first, Iter last) {
// ...
if (*last < *first)
swap(*first, *last);
}
это найдет своп специально для сравниваемого типа (т. е. a swap
определено в том же пространстве имен, что и этот тип), если он есть (через поиск, зависящий от аргумента), и std::swap
если ни один не определен для типа (через using namespace std;
).
это может повлиять на производительность-если они написали своп специально для своего типа, вы можете ожидать, что это потому, что, делая это, они могут обеспечить лучшую производительность. Те средства это явно указывает std::swap
может работать, но, вероятно, приведет к низким результатам.
в противном случае, это почти полностью вопрос удобства и читаемости - я в основном предпочитаю давать полные имена (например, std::swap
) за исключением ситуации, как указано выше, где (в то время, когда я пишу код) любой из по крайней мере двух возможностей может быть предпочтительным, и я хочу дать компилятору достаточную свободу действий, чтобы выбрать правильный.
в другой раз я нахожу использование деклараций/директив полезно, когда пространства имен становятся действительно глубоко вложенными. Boost (для одного очевидного примера) имеет некоторые имена, которые были бы слишком длинными для удобного использования, если вы использовали полное имя каждый раз. Это было особенно верно для (Теперь, к счастью, в основном устаревшей) библиотеки Boost Lambda, где вы использовали заполнители, такие как _1
, это закончилось бы чем-то вроде boost::lambda::placeholders::_1
(но я иду по памяти, так что это, вероятно, по крайней мере частично неправильно), если вы настаивали при использовании полного имени. Это в первую очередь разрушило бы большую часть цели использования библиотеки лямбда.
нет никакого увеличения производительности или штрафа вообще. Все вызовы и переменные разрешаются во время компиляции.
выбор между тремя несколько субъективен. Да,using namespace <ns>;
иногда хмурится за загрязнение глобального пространства имен,но Я думаю, что это безопасно использовать для небольших файлов.
Я склонен использовать второй для целей тестирования, где я ожидаю конфликтов, но я бы просто удалил его после этого. Это может получить сложнее, потому что вы можете закончить вверх с комбинациями как квалифицированных, так и неквалифицированных имен:
vector<std::string> x;
потому что у вас есть using std::vector;
вверху, но не using std::string;
.
Я предпочитаю третий.
существует нулевое влияние на производительность вашего кода, это чисто время компиляции. Это может (теоретически) оказать некоторое влияние на время компиляции, но я сомневаюсь, что это когда-либо достигнет измеримых пропорций.
using namespace std
(или любое другое пространство имен, если на то пошло) определенно следует избегать в заголовочных файлах, которые могут быть включены в любом месте, и введение символов в них может привести к двусмысленности.
как правило, пространства имен существуют, чтобы избежать столкновений имен и using namespace
уничтожит эти цели. Как и using the_namespace::some_id
в меньшей степени. На ваш вопрос нет определенного ответа, но я обычно следую этим правилам:--11-->
-
никогда поставить
using namespace
в заголовочном файле. - избежать
using namespace
иusing
, если это не может сэкономить огромное количество ввода. При необходимости используйте псевдонимы пространства имен (то естьnamespace abbrv = some_really::long_and::nested_namespace;
). - попробуйте ограничить область
using
: вы можете поместить это в функции и блоки, а также область пространства имен. То есть, если у вас есть функция регистрации в вашем .cpp-файл, поставитьusing std::cout;
иusing std::endl;
(или что бы вы ни использовали) в тело функции, а не в область файла.
основная причина в том, что это может привести к двусмысленностям (как для компилятора, так и для человеческого читателя), и это также может замедлить компиляцию (но это не такая большая проблема, как первое)