"использование пространства имен" в заголовках c ++ - PullRequest
107 голосов
/ 01 мая 2011

На всех наших курсах c ++ все учителя всегда ставят using namespace std; сразу после #include s в своих .h файлах.Это кажется мне опасным с тех пор, включив этот заголовок в другую программу, я получу импортированное в мою программу пространство имен, возможно, не осознавая, не намереваясь и не желая этого (включение заголовка может быть очень глубоко вложенным).

Поэтому мой вопрос двойной: я прав, что using namespace не следует использовать в заголовочных файлах, и / или есть ли способ отменить его, что-то вроде:

//header.h
using namespace std {
.
.
.
}

Еще один вопрос в том жеСтроки: Если заголовочный файл #include нужен всем заголовкам, которым он соответствует .cpp, нужны только те заголовки, которые необходимы для определений заголовков, и пусть .cpp file #include остальные или нет, и объявляют все, что ему нужноas extern?
Причина вопроса та же, что и выше: я не хочу сюрпризов при включении файлов .h.

Также, если я прав, это распространенная ошибка?Я имею в виду в реальном программировании и в «реальных» проектах.

Спасибо.

Ответы [ 9 ]

103 голосов
/ 01 мая 2011

Вы определенно НЕ должны использовать using namespace в заголовках именно по той причине, по которой вы говорите, что это может неожиданно изменить значение кода в любых других файлах, которые содержат этот заголовок.Нет способа отменить using namespace, что является еще одной причиной, по которой он так опасен.Обычно я просто использую grep или тому подобное, чтобы убедиться, что using namespace не вызывается в заголовках, а не пробую что-нибудь более сложное.Вероятно, статические средства проверки кода также отмечают это.

Заголовок должен включать только заголовки, необходимые для компиляции.Простой способ обеспечить это - всегда включать собственный заголовок каждого исходного файла в первую очередь, перед любыми другими заголовками.Тогда исходный файл не будет скомпилирован, если заголовок не является автономным.В некоторых случаях, например, ссылаясь на классы деталей реализации в библиотеке, вы можете использовать декларации пересылки вместо #include, потому что вы полностью контролируете определение такого класса, объявленного форвард.

Я не являюсьКонечно, я бы назвал это распространенным явлением, но оно определенно появляется время от времени, обычно написанное новыми программистами, которые не знают о негативных последствиях.Как правило, небольшое информирование о рисках решает любые проблемы, поскольку их относительно легко исправить.

22 голосов
/ 01 мая 2011

Пункт 59 в «Стандартах кодирования C ++ Саттера и Александреску: 101 правила, руководящие указания и лучшие практики»:

Не записывайте использование пространства имен в заголовочном файле или перед #include.108

Названия всех руководств приведены на http://www.gotw.ca/publications/c++cs.htm,, но подробности обязательны для прочтения для разработчиков C ++.

12 голосов
/ 01 мая 2011

Вы должны быть осторожны при включении заголовков внутри заголовков.В больших проектах это может создать очень запутанную цепочку зависимостей, которая запускает большие / более длинные перестройки, чем было на самом деле необходимо.Прочтите эту статью и ее продолжение , чтобы узнать больше о важности хорошей физической структуры в проектах C ++.

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

Что касается пространств имен, я склонен использоватьЯвная область пространства имен в моих заголовочных файлах, и только добавьте using namespace в мои cpp файлы.

6 голосов
/ 02 мая 2011

Ознакомьтесь со стандартами кодирования Центра космических полетов им. Годдарда (для C и C ++). Это оказывается немного сложнее, чем раньше - см. Обновленные ответы на вопросы SO:

Стандарт кодирования GSFC C ++ гласит:

§3.3.7 Каждый заголовочный файл должен #include файлы, необходимые для компиляции, вместо того, чтобы заставлять пользователей #include необходимые файлы. #includes должно быть ограничено тем, что нужно заголовку; другие #includes должны быть помещены в исходный файл.

Первый из вопросов с перекрестными ссылками теперь включает цитату из стандарта кодирования GSFC C и обоснование, но суть в итоге остается той же.

5 голосов
/ 01 мая 2011

Вы правы, что using namespace в заголовке опасно. Я не знаю, как отменить это. Это легко обнаружить, однако просто ищите using namespace в заголовочных файлах. По этой последней причине это редко встречается в реальных проектах. Более опытные коллеги скоро будут жаловаться, если кто-то сделает что-то подобное.

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

4 голосов
/ 26 февраля 2016

Относительно "Есть ли какой-нибудь способ отменить [объявление using]?"

Я думаю, что полезно указать, что на using объявлениях влияет область действия.1006 *

Так что да.Ограничивая область действия декларации using, ее действие действует только в этой области;это «отменено», когда эта область заканчивается.

Когда объявление using объявляется в файле вне какой-либо другой области, оно имеет область действия файла и влияет на все в этом файле.

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

4 голосов
/ 01 мая 2011

Как и все в программировании, прагматизм должен победить догматизм, ИМО.

Пока вы принимаете решение в рамках всего проекта («Наш проект широко использует STL, и мы не хотим добавлять все с помощью std ::.»), Я не вижу в этом проблемы. В конце концов, единственное, чем вы рискуете, это коллизиями имен, и с распространенностью STL это вряд ли станет проблемой.

С другой стороны, если это было решение одного разработчика в одном (не частном) заголовочном файле, я могу видеть, как это вызовет путаницу среди команды, и ее следует избегать.

4 голосов
/ 01 мая 2011

Вы правы. И любой файл должен включать только заголовки, необходимые для этого файла. Что касается "делает что-то неправильно в обычных проектах?" - о да!

2 голосов
/ 16 ноября 2014

Я полагаю, что вы можете безопасно использовать 'using' в заголовках C ++, если вы пишете свои объявления во вложенном пространстве имен следующим образом:

namespace DECLARATIONS_WITH_NAMESPACES_USED_INCLUDED
{
    /*using statements*/

    namespace DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED
    {
        /*declarations*/
    }
}

using namespace DECLARATIONS_WITH_NAMESPACES_USED_INCLUDED::DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED;

Это должно включать только вещи, объявленные в 'DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED' без пространств имениспользуемый.Я проверил это на компиляторе mingw64.

...