На всех наших курсах по C ++ все учителя всегда ставят using namespace std;
сразу после #include
s в своих .h
файлах. Мне это кажется опасным, поскольку с тех пор, включив этот заголовок в другую программу, я получу пространство имен, импортированное в мою программу, возможно, не осознавая, не намереваясь или не желая этого (включение заголовка может быть очень глубоко вложенным).
Итак, мой вопрос двоякий: я прав, что using namespace
не следует использовать в файлах заголовков, и / или есть какой-то способ отменить это, например:
//header.h
using namespace std {
.
.
.
}
Еще один вопрос в том же духе: должен ли файл заголовка #include
все заголовки, которые .cpp
нужны соответствующему файлу, только те, которые необходимы для определений заголовков, и позволить .cpp
файлу #include
остальное или ничего и объявить все, что ему нужно, как extern
?
Причина вопроса такая же, как и выше: я не хочу сюрпризов при включении .h
файлов.
Кроме того, если я прав, это распространенная ошибка? Я имею в виду программирование в реальном мире и «настоящие» проекты.
Спасибо.
источник
using namespace
операторов, вы можете использовать полное имя для решения проблемы.Ответы:
Вам определенно НЕ следует использовать
using namespace
в заголовках именно по той причине, по которой вы говорите, что это может неожиданно изменить значение кода в любых других файлах, которые включают этот заголовок. Невозможно отменить действие,using namespace
что является еще одной причиной его опасности. Я обычно просто используюgrep
или что-то подобное, чтобы убедиться, чтоusing namespace
он не вызывается в заголовках, вместо того, чтобы пытаться что-то более сложное. Вероятно, это тоже отмечают средства проверки статического кода.Заголовок должен включать только те заголовки, которые ему необходимы для компиляции. Простой способ обеспечить это - всегда включать собственный заголовок каждого исходного файла в первую очередь перед любыми другими заголовками. Тогда исходный файл не скомпилируется, если заголовок не является самодостаточным. В некоторых случаях, например при обращении к классам деталей реализации в библиотеке, вы можете использовать форвардные объявления вместо того,
#include
чтобы иметь полный контроль над определением такого прямого объявленного класса.Я не уверен, что назвал бы это обычным явлением, но он определенно появляется время от времени, обычно написанный новыми программистами, которые не осознают негативных последствий. Обычно небольшое просвещение о рисках решает любые проблемы, поскольку их относительно просто исправить.
источник
using
инструкции в наших.cpp
файлах? в3rdPartyLib::BigClassName<3rdPartyLib::AnotherBigName,3rdPartyLib::AnotherBigName>::Iterator
s является смертью до кончиков пальцев.template
функции - которые должны быть в заголовках?typedefs
?using
операторы в.cpp
файлах, потому что область действия будет ограничена только этим файлом, но никогда не делайте этого перед#include
оператором. Что касается шаблонных функций, определенных в заголовках, к сожалению, я не знаю хорошего решения, кроме простого написания пространства имен ... Возможно, вы могли бы поместитьusing
объявление в отдельную область видимости{ /* using statement in between brackets */ }
, что, по крайней мере, предотвратило бы его выход из текущего файла ,Пункт 59 в книге Саттера и Александреску «Стандарты программирования C ++: 101 правила, рекомендации и передовой опыт» :
Заголовочный файл является гостевым файлом в одном или нескольких исходных файлах. Заголовочный файл, который включает
using
директивы и объявления, тоже привлекает к себе внимание его шумных приятелей.using
Декларация приносит приятель.using
Директива приносит во всех приятелях в пространстве имен. Ваши учителяusing namespace std;
используют директиву using.А если серьезно, у нас есть пространства имен, чтобы избежать конфликта имен. Заголовочный файл предназначен для предоставления интерфейса. Большинство заголовков не зависит от того, какой код может их включать сейчас или в будущем. Добавление
using
операторов для внутреннего удобства в заголовок навязывает эти удобные имена всем потенциальным клиентам этого заголовка. Это может привести к конфликту имен. И это просто грубо.источник
Будьте осторожны при включении заголовков внутри заголовков. В больших проектах он может создавать очень запутанную цепочку зависимостей, которая запускает более крупные / более длительные перестройки, чем было действительно необходимо. Прочтите эту статью и последующие статьи, чтобы узнать больше о важности хорошей физической структуры в проектах C ++.
Вы должны включать заголовки в заголовок только тогда, когда это абсолютно необходимо (когда требуется полное определение класса), и использовать предварительное объявление везде, где вы можете (когда требуется класс, это указатель или ссылка).
Что касается пространств имен, я обычно использую явную область видимости пространства имен в своих файлах заголовков и помещаю только
using namespace
в свои файлы cpp.источник
template
объявление функции? что должно происходить в заголовке, нет?Ознакомьтесь со стандартами кодирования Goddard Space Flight Center (для C и C ++). Это оказалось немного сложнее, чем раньше - см. Обновленные ответы на вопросы SO:
Стандарт кодирования GSFC C ++ гласит:
Первый из вопросов с перекрестными ссылками теперь включает цитату из стандарта кодирования GSFC C и обоснование, но суть остается прежней.
источник
Вы правы, что
using namespace
в шапке опасно. Я не знаю, как это исправить. Обнаружить это несложно, однако достаточно выполнить поискusing namespace
в файлах заголовков. По этой последней причине это нечасто в реальных проектах. Более опытные коллеги скоро будут жаловаться, если кто-то сделает что-то подобное.В реальных проектах люди стараются минимизировать количество включаемых файлов, потому что чем меньше вы включаете, тем быстрее он компилируется. Это экономит время каждого. Однако, если заголовочный файл предполагает, что что-то должно быть включено перед ним, он должен включать это само. В противном случае он делает заголовки несамостоятельными.
источник
Ты прав. И любой файл должен включать только заголовки, необходимые для этого файла. Что касается "делать что-то неправильно в реальных проектах?" - о да!
источник
Как и все в программировании, прагматизм должен победить догматизм, ИМО.
Пока вы принимаете решение в масштабе всего проекта («Наш проект широко использует STL, и мы не хотим, чтобы все добавлялось с помощью std ::.»), Я не вижу в этом проблемы. В конце концов, единственное, чем вы рискуете, так это конфликтом имен, а с повсеместным распространением STL это вряд ли станет проблемой.
С другой стороны, если бы это было решение одного разработчика в одном (не закрытом) заголовочном файле, я могу видеть, как это могло бы вызвать путаницу в команде, и этого следует избегать.
источник
Что касается вопроса «Есть ли способ отменить [
using
объявление]?»Думаю, полезно отметить, что на
using
объявления влияет область видимости.Так что да. Ограничивая область действия
using
объявления, ее действие длится только в пределах этой области; он «отменяется», когда этот объем заканчивается.Когда
using
объявление объявляется в файле за пределами любой другой области, оно имеет файловую область и влияет на все в этом файле.В случае файла заголовка, если
using
объявление находится в области видимости файла, это будет распространяться на область действия любого файла, в который включен заголовок.источник
namespace
материал объявления) и как он на самом деле работает (например, переменная).{}
включение его ограничивает его объем,{}
после того как он ничего не делает с ним. Это случайный способusing namespace
глобального применения.Я считаю, что вы можете безопасно использовать 'using' в заголовках C ++, если вы пишете свои объявления во вложенном пространстве имен следующим образом:
Это должно включать только то, что объявлено в 'DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED' без используемых пространств имен. Я тестировал его на компиляторе mingw64.
источник
using
объявлений внутри определений функций там, где я могу, чтобы они не загрязняли пространства имен вне функции. Но теперь я хочу использовать определяемые пользователем литералы C ++ 11 в файле заголовка, и, согласно обычному соглашению, буквальные операторы защищены пространством имен; но я не хочу использовать их в списках инициализаторов конструктора, которые не входят в область, в которой я могу использовать объявление, не загрязняющее окружающую средуusing
. Так что это отлично подходит для решения этой проблемы.error: ... DECLARATIONS_WITH_NAMESPACES_USED_INCLUDED:: DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED::ClassName ...
. По крайней мере, это то, что со мной происходит в g ++.