Використовувати `using` в C ++ чи уникати цього?


17

Знижка на дуже різну семантику завдяки ADL, як я взагалі повинен користуватися usingі чому? Це залежить від ситуації (наприклад, заголовок, який буде #included та вихідний файл, який не буде)?

Також я повинен віддати перевагу ::std::або std::?

  1. Рівень простору імен using namespace:

    using namespace std;
    
    pair<string::const_iterator, string::const_iterator>
    f(const string &s) {
        return make_pair(s.begin(), s.end());
    }
    
  2. Будучи повністю явним:

    std::pair<std::string::const_iterator, std::string::const_iterator>
    f(const std::string &s) {
        return std::make_pair(s.begin(), s.end());
    }
    
  3. Рівень простору імен за допомогою оголошень:

    using std::pair;
    using std::string;
    
    pair<string::const_iterator, string::const_iterator>
    f(const string &s) {
        return make_pair(s.begin(), s.end());
    }
    
  4. Функція-локальне використання-декларацій:

    std::pair<std::string::const_iterator, std::string::const_iterator>
    f(const std::string &s) {
        using std::make_pair;
        return make_pair(s.begin(), s.end());
    }
    
  5. Функція локальна using namespace:

    std::pair<std::string::const_iterator, std::string::const_iterator>
    f(const std::string &s) {
        using namespace std;
        return make_pair(s.begin(), s.end());
    }
    
  6. Щось ще?

Це передбачається попереднє значення C ++ 14, а отже, не використовується вирахування типу повернення auto.


2
Див. Stackoverflow.com/questions/1265039/using-std- namespace для початкової точки.
AProgrammer

@AProgrammer: А, дякую за посилання, яке відповідає частині мого запитання. :) Тим НЕ менш цікаво про ::std::VS. std::ж.
користувач541686

4
Я використовую stdбез другого, хоча. Хтось, що визначає простір імен std, задає проблеми (і, ймовірно, шукає, щоб скористатися тим, що більшість людей використовує, stdа не ::std).
AProgrammer

Відповіді:


25

Уникайте використання usingзаголовків, оскільки це порушує призначення просторів імен.

Це нормально використовувати його у вихідних файлах, але я б все-таки уникав цього в деяких випадках (наприклад using std).

Однак якщо у вас є вкладені простори імен, це нормально:

namespace A {
namespace B {
namespace C {
class s;
} // C
} // B
namespace D{
using B::C::s;
} // D
} // A

6
+1 дивовижно, скільки навчальних посібників та курсів для коледжів просто говорять вам про використання usingключового слова без ретельного пояснення того, чому для початку використовуються простори імен.
Jeffrey Sweeney

Люди хочуть продовжувати користуватися iostreams, рядками тощо. Вони не хочуть вводити std :: кожен раз, коли вони хочуть використовувати якусь річ, або повинні пам’ятати ще один шматок котла, який потрібно поставити перед своїм кодом, що призведе до менш корисних помилок, якщо вони забудуть його . :(
Колен

Буде щось на зразок typedef std :: string sstring; бути альтернативою?
Джорджіо

1
@Colen: Цими бідними душами можуть користуватися using std::coutі друзі, але це не так, як coutце вже жахливо довге ім'я.
Бенджамін Баньє

1
Якщо ви студент коледжу в перший день "мого першого класу C ++", це ще одна річ, яка може викликати синтаксичні помилки, які ви не розумієте. Нам легко зрозуміти, тому що ми досвідчені програмісти, але коли ти намагаєшся вивчити мову, то інше, що ти повинен турбуватися про те, що тобі не потрібно.
Колен

11

Вкладаючи оператор з використанням у вихідний файл, МОЛЯ, просто втягніть потрібні речі. Наприклад:

using std::string;
using std::ostringstream;

Проблема тут полягає в тому, що якщо ви це зробите

using namespace std;

ви втягуєте КОЖНЕ ОДИНЕ ЧИСТО з std у глобальний простір імен. Це призводить до дуже цікавих повідомлень про помилки, коли ви випадково використовуєте в коді ім’я, яке відповідає тому, про яке ви абсолютно не знали в std. Якщо ви просто втягнете потрібні речі, у вас не виникне цієї проблеми (або, точніше, у наступного програміста, який працює над вашим кодом, ця проблема не буде).


Крім того, ви можете using namespaceпросто в області функцій, уникаючи проблеми.
Tamás Szelei

2
@fish - фактично використання простору імен в області функцій не уникне проблеми, це просто обмежує простір, де все може піти не так. І якщо ви в кінцевому підсумку вкладаєте "використовувати простір імен" у кожну функцію, це не сильно відрізняється від того, щоб це робити в усьому світі.
Майкл Коне

Хоча C ++ дійсно дозволяє оголошувати типи на рівні функції, це не є звичайною справою; крім цього можливі зіткнення імен легко помітити з виводу компілятора (але ви праві, що це їм не заважає).
Tamás Szelei

2

Як вказує VJovic, не використовуйте usingу заголовку файл. usingу файлі заголовка впливає на поточний блок компіляції (файл .cpp) таким чином, що вихідний файл може не очікувати.

using namespaceтакож слід уникати у вихідному файлі. Це приводить кожен символ до тієї ж області, що і вихідний файл. Вашим читачам зрозуміліше, що ви робите, якщо використовуєте конкретні символи з простору імен.


2
З практичної using namespace JoystickModuleточки зору , якщо ваш код не перекриває загальновживані імена, я б швидше побачив на початку .cpp-файл, ніж JoystickModule::прикріплений до кожного об'єкта впродовж.
Алекс П

@AlexP: Саме так я це роблю. Одне usingтвердження для мого власного простору імен, над яким я зараз працюю, а все інше залишається просторим.
Бенджамін Клостер

Я повинен детальніше зупинитися на "використанні конкретних символів з простору імен". Замість того, щоб префіксувати кожен символ у кожному використанні, що не допомагає читати, я вважаю за краще використовувати явні підйомні символів. using SomeNameSpace::SomeSymbol. Це дозволяє уникнути переміщення кожного символу з простору імен у поточну область.
Білл Двері

0

Писання usingв заголовках - найкращий спосіб створити всілякі неприємні та неможливі налагодження помилок. Ви НЕ робити цього.

Писати using namespace XYZу вихідний файл трохи краще, але все одно може завдати вам незліченних головних болів. Безпечний спосіб - чітко вказати, що ви використовуєте, наприклад using Foo::Bar.

Скажімо, у вас є Bar.cpp із наступним:

//Bar.cpp
using namespace Foo;
namespace
{
    double increment(double v) { return (v + 1); }
}

void Bar::someFunction()
{
    //...
    int currentIndex = 0;
    int nextIndex = increment(currentIndex);
    //...
}

Функція справно працювала, поки одного дня - здавалося б, без змін коду у відповідних класах - її поведінка змінилася: раптом currentIndexзавжди, здається , хтось вимкнений . Переглядаючи останні зміни, ви не виявляєте жодних змін, навіть віддалених щодо коду.

Зрештою ви виявите причину:
Ви (опосередковано) Foo.hдесь включаєтесь . У файлах для простору імен Foo була додана нова функція:

//Foo.h
namespace Foo
{
    //...
    int& increment(int& v) { v += 1; return v; };
    //...
}

Що для вас відповідає кращому, increment(int)ніж ваша функція increment(double)- тепер замість цього Foo::increment()функція викликається Bar::someFunction(). Уопс.

(І якби ви писали usingв заголовках, які using namespace Fooцілком можуть бути в будь-якому місці вашого дерева включення ...)

Отже ... Не пишіть жодної usingу заголовки, а також пильнуйте про те, щоб писати using namespaceу вихідні файли.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.