Мне интересно немного о namespace
а также using
В основном, в C ++ я хотел бы знать различия и выяснить, как использовать его наилучшим образом.
На мой взгляд, есть (по крайней мере) три способа определения имени класса, и я не уверен, как выбрать среди них:
using namespace <namespace>
using <namespace>::<what_to_use>
<namespace>::<what_to_use> <use_it>
Я хотел бы знать о преимуществах, особенно, если производительность связана с тем или иным способом, если это просто синтаксический и вопрос предпочтений, или если есть другие вещи, которые я не учел по этому поводу.
Во-первых использование директивы пространства имен, он приносит все имена символов из указанного пространства имен в текущем пространстве имен, независимо от того, нужны они вам или используются. Конечно, нежелательно.
Второй используя объявление пространства имен. Он приносит только указанное имя символа в текущем пространстве имен. Преимущество в том, что вам не нужно вводить полное имя каждый раз.
Третий полностью уточненные имена символа. Недостатком является то, что вы должны вводить полное имя везде, где вы используете символ.
Понятно, Второй & В-третьих, более подходящие. Там нет разницы в производительности ни в одном из них. Разница лишь в количестве набираемых символов. Просто выберите любой из них в зависимости от того, что указано в вашем стандарте кодирования.
РЕДАКТИРОВАТЬ:
Как указывает @Jerry, использование объявления в сочетании с ADL (поиск, зависящий от аргумента) может привести к нежелательным последствиям.
Вы можете найти подробное объяснение в одном из моих ответов:
Подробное объяснение того, как поиск Кенига работает с пространствами имен и почему это хорошо?
под разделом,
Почему критика алгоритма Кенига?
Существует одна (по общему признанию, несколько необычная) ситуация, когда форма, которую вы используете, действительно может иметь значение, и форма, которую вы хотите использовать является 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);
}
Это найдет своп специально для сравниваемого типа (т.е. 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
в меньшей степени. На ваш вопрос нет однозначного ответа, но я обычно придерживаюсь следующих правил:
using namespace
в заголовочном файле.using namespace
а также using
, если это не может сэкономить огромное количество печатания. При необходимости используйте псевдонимы пространства имен (то есть namespace abbrv = some_really::long_and::nested_namespace;
).using
: вы можете поместить это в функции и блоки, а также в область имен. То есть, если у вас есть функция регистрации в вашем файле .cpp, поместите using std::cout;
а также using std::endl;
(или что вы используете) в тело функции, а не в область видимости файла.Основная причина в том, что это может привести к неоднозначности (как для компилятора, так и для читателя), а также может замедлить саму компиляцию (но это не такая большая проблема, как первое)