Использование классов STL без включения их соответствующих заголовков

Рассмотрим этот код:

#include <vector>

struct S { };

int main()
{
 std::vector<int> v;
 // Do whatever work I need to with v

 // Oh, by the way, I also need std::allocator for something else...
 std::allocator<s> a;
 S s;
 a.construct(&s, S());
 a.destroy(&s);
}
</s></int></vector>

std::allocator объявлен в , но я не включил этот заголовок.

Вопросов:

  1. Могу ли я по-прежнему полагаться на то, что std::allocator будет полностью использоваться при включении ? Почему, почему нет?

  2. Если да, то какие другие классы я могу полагаться на то, чтобы быть включенными косвенно и при каких условиях? (Есть ли список где-нибудь, или я должен был бы выяснить их вручную?)

  3. Является ли хорошей практикой избегать включения конкретного заголовка (например, ), если вы уже включили другой заголовок, который подразумевает включение класса, который вам нужен? Почему, почему нет?

2 ответа

Стандарт C++ позволяет любому стандартному заголовку включать произвольное количество других стандартных заголовков. Однако это почти никогда не требовалось.

Например, достаточно распространять информацию о detail реализации в пространстве имен detail, а затем извлекать имена оттуда, чтобы стать общедоступными, если и только если пользователь включил заголовок, который должен сделать их видимыми.

Другими словами, если вы используете что-то, включите заголовок. Это на самом деле довольно распространенный источник проблем. С более старыми компиляторами, в том числе один заголовок, часто заканчивалось определение того, что этот заголовок не требуется определять. Новые компиляторы, как правило, более гранулированы, поэтому многим старым кодам требуется небольшое исправление, чтобы включить соответствующие заголовки, прежде чем он будет работать правильно. Хотя это не самая большая проблема с переносимостью, которая возникает, это достаточно раздражает, что явно лучше избегать ее, когда вы можете.

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


Либо стандарт предоставляет гарантию, либо нет. Если это не так, у вас нет гарантии. Аргумент "подразумевает, что включение" терпит неудачу, потому что компилятор не должен включать в себя больше того класса, который ему нужен, и, очевидно, что-то, что вы делаете с классом, больше, чем нужно.

licensed under cc by-sa 3.0 with attribution.