Подтвердить что ты не робот

Почему включение "использования пространства имен" в файл заголовка - плохая идея на С++?

При чтении от Брюса Эккеля "Думая на С++" об пространствах имен, я столкнулся с следующим утверждением:

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

Не могли бы вы помочь мне понять приведенное выше выражение с помощью простого примера?

4b9b3361

Ответ 1

Рассмотрим эту программу:

line#
    1 #include <string>                                                               
    2                                                                                 
    3 using namespace std;                                                            
    4                                                                                 
    5 struct string { const char* p; };  // Beware: another string!
    6                                                                                 
    7 int main()                                                                      
    8 {                                                                               
    9     string x; // Error: ambiguous - which string is wanted?
   10 }

Если вы попытаетесь скомпилировать его, вы увидите ошибки:

g++     using.cc   -o using
using.cc: In function `int main()':
using.cc:9: error: use of `string' is ambiguous
using.cc:5: error:   first declared as `struct string' here
/usr/lib/gcc/i386-redhat-linux/3.4.6/../../../../include/c++/3.4.6/bits/stringfwd.h:60: error:
   also declared as `typedef struct std::basic_string<char, std::char_traits<char>, std::allocator<char> > std::string' here
using.cc:9: error: `string' was not declared in this scope
using.cc:9: error: expected `;' before "x"

Проблема заключается в том, что когда main() указывает string x;, компилятор не уверен, требуется ли пользовательский ::string или включенный std::string.

Теперь представьте, что вы берете верхнюю часть программы... строки с 1 по 5 - вплоть до struct string и включаете ее в файл заголовка, который затем #include до main(). Ничего не меняется: у вас все еще есть ошибка. Таким образом, как и для автономных программ, заголовочные файлы с операторами using в них могут вызывать проблемы для другого кода, который включает их, делая некоторые из своих операторов двусмысленными.

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

  • удаление инструкции using из заголовка или
  • изменение содержимого <string> или любого другого заголовка, влияющего на std::

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

Тем не менее, если заголовок имеет только "использование" внутри класса или функции, тогда нет никакого влияния на код за пределами этой области, поэтому потенциальное влияние изменений на std:: значительно уменьшается.

Ответ 2

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

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

Ответ 3

Ну, в чем смысл использования пространств имен. Во избежание риска столкновения имен.

Скажем, что у вас есть довольно распространенное имя класса, например FooBar. Если вы используете несколько библиотек, существует риск того, что FooBar в библиотеке A столкнется с FooBar в библиотеке B. Для этого мы используем два разных пространства имен A и B для перемещения FooBars из глобального пространства имен в A:: FooBar и B:: FooBar (поэтому они сохраняются отдельно друг от друга).

Если вы поместите using A; и using B; в заголовки, это переместит A:: FooBar и B:: FooBar только в FooBar, вернув столкновение, удалив выигрыш от использования пространств имен в первую очередь.

Ответ 4

Скопируйте следующий абзац из "С++ Primer, пятое издание":

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