"использование пространства имен" в заголовках С++

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

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

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

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

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

Спасибо.

+105
01 мая '11 в 15:49
источник поделиться
9 ответов

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

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

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

+97
01 мая '11 в 16:24
источник

Связанные вопросы


Похожие вопросы

Пункт 59 в Sutter и Alexandrescu "Стандарты кодирования С++: 101 Правила, рекомендации и лучшие практики":

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

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

+21
01 мая '11 в 16:41
источник

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

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

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

+12
01 мая '11 в 16:12
источник

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

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

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

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

+6
01 мая '11 в 21:11
источник

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

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

+5
01 мая '11 в 15:55
источник

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

+4
01 мая '11 в 15:52
источник

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

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

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

+3
01 мая '11 в 16:29
источник

Что касается "Есть ли способ отменить [a using декларация]?"

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

#include <vector>

{   // begin a new scope with {
    using namespace std;
    vector myVector;  // std::vector is used
}   // end the scope with }

vector myOtherVector;   // error vector undefined
std::vector mySTDVector // no error std::vector is fully qualified

Так эффективно да. Ограничивая объем объявления using, его эффект сохраняется только в пределах этой области; он "отменен", когда эта область заканчивается.

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

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

+3
26 февр. '16 в 18:27
источник

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

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.

+3
16 нояб. '14 в 17:42
источник

Посмотрите другие вопросы по меткам или Задайте вопрос