"использование пространства имен" в заголовках c++
во всех наших курсах c++, все учителя всегда ставят using namespace std; сразу после #includeв их .h файлы. Это кажется мне опасным с тех пор, включив этот заголовок в другую программу, я получу пространство имен, импортированное в мою программу, возможно, не осознавая, намереваясь или желая его (включение заголовка может быть очень глубоко вложенным).
так что мой вопрос двойной: я прав, что using namespace не следует использовать в заголовочных файлах, и/или есть ли способ, чтобы отменить это, что-то вроде:
//header.h
using namespace std {
.
.
.
}
еще один вопрос в том же духе: должен ли заголовочный файл #include все заголовки, что он соответствует .cpp файл нуждается, только те, которые необходимы для определения заголовка и пусть .cpp file #include остальные, или нет и объявить все, что ему нужно, как extern?
Аргументация вопроса такая же, как и выше: я не хочу сюрпризов при включении .h файлы.
кроме того, если я прав, это распространенная ошибка? Я имею в виду в реальном программировании и в "реальных" проектах там.
спасибо.
9 ответов:
вы определенно не должны использовать
using namespaceв заголовках именно по той причине, что вы говорите, что он может неожиданно изменить значение кода в любых других файлах, которые включают этот заголовок. Нет никакого способа, чтобы отменитьusing namespaceЭто еще одна причина, по которой это так опасно. Я обычно просто используюgrepили тому подобное, чтобы убедиться, чтоusing namespaceне вызывается в заголовках, а не пытается что-то более сложное. Вероятно, статические кодовые шашки тоже отмечают это.заголовок должен включите только заголовки, которые ему нужно скомпилировать. Простой способ обеспечить это-всегда включать собственный заголовок каждого исходного файла в качестве первого, перед любыми другими заголовками. Тогда исходный файл не будет компилироваться, если заголовок не является автономным. В некоторых случаях, например со ссылкой на классы сведений о реализации в библиотеке, можно использовать прямые объявления вместо
#includeпотому что у вас есть полный контроль над определением такого прямого объявленного класса.Я не уверен, что я бы назвал его общим, но он определенно появляется время от времени, обычно написанный новыми программистами, которые не знают о негативных последствиях. Как правило, только небольшое образование о рисках заботится о любых проблемах, так как это относительно просто исправить.
пункт 59 В Саттере и Александреску "стандарты кодирования C++: 101 правила, рекомендации и лучшие практики":
- не записывайте использование пространства имен в заголовочный файл или перед #include. 108
названия всех руководящих принципов находятся в http://www.gotw.ca/publications/c++cs.htm, но детали должны быть прочитаны для разработчиков C++.
вы должны быть осторожны при включении заголовков внутри заголовков. В больших проектах это может создать очень запутанную цепочку зависимостей, которая запускает большие / более длинные перестроения, чем было на самом деле необходимо. Проверьте в этой статье и по ее итогам чтобы узнать больше о важности хорошей физической структуры в проектах c++.
вы должны включать заголовки только внутри заголовка, когда это абсолютно необходимо (всякий раз, когда полное определение класса необходимо), и использовать прямое объявление везде, где вы можете (когда класс требуется указатель или ссылка).
Что касается пространств имен, я обычно использую явную область пространства имен в моих заголовочных файлах и только помещаю
using namespaceв моих файлах cpp.
Проверьте стандарты кодирования Центра космических полетов Годдарда (для C и c++). Это оказывается немного сложнее, чем раньше-см. обновленные ответы на вопросы SO:
стандарт кодирования GSFC C++ гласит:
§каждый заголовочный файл должен 3.3.7
#includeфайлы, которые необходимо скомпилировать, вместо того, чтобы заставлять пользователей#includeнеобходимые файлы.#includesдолжно быть ограничено тем, что нужно заголовку; другое#includesдолжен быть помещен в исходный файл.первый из перекрестных вопросов теперь включает цитату из стандарта кодирования GSFC C и обоснование, но суть в конечном итоге остается той же.
Вы правы, что
using namespaceв заголовке опасно. Я не знаю, как это исправить. Это легко обнаружить, однако просто искатьusing namespaceв заголовочных файлах. По этой последней причине он редко встречается в реальных проектах. Более опытные сотрудники скоро будут жаловаться, если кто-то делает что-то подобное.в реальных проектах люди стараются минимизировать количество файлов, ведь чем меньше вы включаете, тем быстрее он компилирует. Это экономит время каждого. Однако если заголовочный файл предполагает, что что-то должно быть включено до него, а затем он должен включать его сам. В противном случае это делает заголовки не самодостаточны.
вы правы. И любой файл должен включать только заголовки, необходимые для этого файла. Что касается "делает ли что-то неправильно в реальных проектах?- о да!
Как и все вещи в программировании, прагматизм должен победить догматизм, ИМО.
пока вы принимаете решение по всему проекту ("Наш проект широко использует STL, и мы не хотим добавлять все с помощью std::."), Я не вижу в этом проблемы. Единственное, чем вы рискуете, это столкновение имен, в конце концов, и с повсеместностью STL это вряд ли будет проблемой.
с другой стороны, если это было решение одного разработчика в одном (non-private) header-file, я вижу, как это вызовет путаницу среди команды и ее следует избегать.
Я считаю, что вы можете использовать "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.
что касается "Есть ли способ отменить [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объявление находится в области file-scope это будет распространяться на область любого файла, в который включен заголовок.