По-перше, деяка термінологія:
- використання-декларація :
using std::vector;
- використання-директива :
using namespace std;
Я думаю, що використання use-директив добре, доки вони не використовуються в глобальній області застосування у заголовковому файлі. Так що маючи
using namespace std;
у вашому .cpp-файлі насправді не є проблемою, і якщо виявиться, він повністю під вашим контролем (і за бажанням його можна навіть охопити до окремих блоків). Я не бачу жодної конкретної причини захаращувати код за допомогою std::
кваліфікації - це просто стає купою зорового шуму. Однак якщо ви не використовуєте std
в своєму коді цілу купу імен з простору імен, я також не бачу проблем із тим, щоб виключати директиву. Це тавтологія - якщо директива не потрібна, не потрібно її використовувати.
Аналогічно, якщо ви можете обійтись за допомогою декількох декларацій з використанням (замість використання директив ) для специфічних типів у std
просторі імен, то немає жодної причини, щоб у вас не було лише тих специфічних імен, що вводяться у поточну область імен. З іншого боку, я вважаю, що було б божевільним і клопотом з бухгалтерського обліку мати 25 або 30 використання декларацій, коли одна директива використання також зробить трюк.
Також добре пам’ятати, що бувають випадки, коли потрібно використовувати декларацію з використанням. Перегляньте "Пункт 25 Скотта Майєра: Розгляньте підтримку заміни, що не кидається" з Ефективного C ++, Третя редакція. Для того, щоб загальна, шаблонна функція використовувала метод "кращого" swap для параметризованого типу, вам потрібно скористатися пошуком, який залежить від декларації та аргументу (як пошук ADL або Koenig):
template< typename T >
void foo( T& x, T& y)
{
using std::swap; // makes std::swap available in this function
// do stuff...
swap( x, y); // will use a T-specific swap() if it exists,
// otherwise will use std::swap<T>()
// ...
}
Я думаю, що ми повинні переглянути загальні ідіоми для різних мов, які суттєво використовують простори імен. Наприклад, Java і C # значною мірою використовують простори імен (можливо, більше, ніж C ++). Найбільш поширений спосіб використання імен в просторах імен на цих мовах - це їх масове приведення в поточний обсяг з еквівалентом директиви використання. Це не спричиняє проблем із широким розповсюдженням, і кілька разів з цією проблемою вирішуються за принципом "виняток", маючи справу з відповідними іменами за допомогою повнокваліфікованих імен або шляхом псевдоніму - як це можна зробити в C ++.
Герб Саттер та Андрій Олександреску про це говорять у "Пункт 59: Не записуйте вживання простору імен у файл заголовка або перед # включенням" своєї книги, Стандарти кодування C ++: 101 Правила, рекомендації та найкращі практики:
Коротше кажучи: Ви можете та маєте використовувати простір імен, використовуючи декларації та директиви вільно у своїх файлах реалізації після #include
директив, і почуватись добре з цим. Незважаючи на неодноразові твердження про протилежне, простір імен з використанням декларацій та директив не є злим, і вони не перешкоджають призначенню просторів імен. Швидше, саме вони роблять простори імен корисними.
Stroupstrup часто цитується: "Не забруднюйте глобальний простір імен" у "Мові програмування на C ++, третє видання". Насправді він говорить про це (C.14 [15]), але посилається на розділ C.10.1, де він говорить:
З допомогою декларування додає ім'я в локальній області видимості. З допомогою директиви робить; він просто надає імена, доступні в обсязі, в якому вони були оголошені. Наприклад:
namespaceX {
int i , j , k ;
}
int k ;
void f1()
{
int i = 0 ;
using namespaceX ; // make names from X accessible
i++; // local i
j++; // X::j
k++; // error: X::k or global k ?
::k ++; // the global k
X::k ++; // X’s k
}
void f2()
{
int i = 0 ;
using X::i ; // error: i declared twice in f2()
using X::j ;
using X::k ; // hides global k
i++;
j++; // X::j
k++; // X::k
}
Місцеве оголошене ім'я (оголошене або звичайною декларацією, або декларацією, що використовує) приховує нелокальні декларації з однойменною назвою, а будь-які незаконні перевантаження імені виявляються в точці декларації.
Зверніть увагу на помилку неоднозначності для k++
в
f1()
. Глобальним іменам не надається перевага перед іменами з просторів імен, доступних у глобальному масштабі. Це забезпечує значний захист від випадкових зіткнень з іменами та, що важливо, - забезпечує відсутність переваг від забруднення глобального простору імен.
Коли бібліотеки, що декларують багато імен, стають доступними через використання директив, суттєвою перевагою є те, що сутички невикористаних імен не вважаються помилками.
...
Я сподіваюся побачити кардинальне зменшення використання глобальних імен у нових програмах із використанням просторів імен порівняно з традиційними програмами C та C ++. Правила для просторів імен були спеціально створені, щоб не надавати переваг "ледачому" користувачеві глобальних імен перед тим, хто дбає про те, щоб не забруднити глобальну сферу.
І як можна мати таку ж перевагу, як "ледачий користувач глобальних імен"? Скориставшись користувачем-директивою, яка безпечно робить імена в просторі імен доступними для поточної області.
Зауважте, що в std
просторі імен є розмежування - імена, доступні для сфери застосування при належному використанні директиви використання (шляхом розміщення директиви після цього #includes
), не забруднюють глобальний простір імен. Це просто зробити ці імена доступними легко та з постійним захистом від сутичок.