"использование пространства имен" в заголовках 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 это будет распространяться на область любого файла, в который включен заголовок.