Почему исключение "#include <string>" только иногда приводит к сбоям компиляции?
Я начинаю с С++. Когда я пишу код, иногда пишу #include <string>
и код работает, в других случаях я не пишу #include <string>
, и код не работает. Но иногда это работает без #include <string>
.
Итак, мне нужно написать #include <string>
, чтобы код работал?
Ответы
Ответ 1
Если вы используете члены, объявленные внутри стандартного заголовка string
, то да, вы должны включить этот заголовок прямо или косвенно (через другие заголовки).
Некоторые компиляторы на некоторых платформах могут в какой-то момент месяца компилироваться, даже если вы не смогли включить заголовок. Такое поведение является неудачным, ненадежным и не означает, что вы не должны включать заголовок.
Причина в том, что вы включили другие стандартные заголовки, которые также включают string
. Но, как я уже сказал, на это вообще нельзя полагаться, и это может также сильно измениться (например, когда установлена новая версия компилятора).
Всегда включать все необходимые заголовки. К сожалению, похоже, нет надежной онлайн-документации, по которой должны быть включены заголовки. Проконсультируйтесь с книгой или официальным стандартом на С++.
Например, следующий код компилируется с моим компилятором (gcc
4.6):
#include <iostream>
int main() {
std::string str;
}
Но если я удалю первую строку, она больше не компилируется, хотя заголовок iostream
должен быть фактически не связан.
Ответ 2
Возможно, что в других заголовках, которые вы делаем, есть #include <string>
.
Тем не менее, как правило, это хорошая идея #include <string>
непосредственно в вашем коде, даже если это не обязательно необходимо для успешной сборки, если эти "другие" заголовки меняются - например, из-за другой (или другой версии) компилятор/стандартная реализация библиотеки, платформа или даже просто конфигурация сборки.
(Конечно, это обсуждение относится к любому заголовку, а не только к <string>
.)
Ответ 3
Хотя в конкретном исходном файле нет прямого появления #include <string>
, это не значит, что он не был включен другим файлом заголовка. Рассмотрим это:
Файл: header.h
#if !defined(__HEADER_H__)
#define __HEADER_H__
// more here
#include <string>
// ...and here
#endif
Файл: source1.cc
#include <string>
void foo()
{
// No error here.
string s = "Foo";
}
Файл: source2.cc
#include <header.h>
void bar()
{
// Still no error, since there a #include <string> in header.h
string s = "Bar";
}
Файл: source3.cc
void zoid()
{
// Here the error; no such thing as "string", since non of the
// previous headers had been included.
string s = "Zoid";
}
Ответ 4
Если вы просто используете указатель/ссылку на определенный пользователем тип, тип должен быть объявлен только:
class my_class;
void foo(const my_class& c);
Но когда вы используете это значение, компилятор должен знать размер и с этим определением типа.
И имейте в виду, что стандартные заголовки могут включать в себя другие, что автоматически не означает, что все реализации делают это, поэтому вы не можете положиться на это.
Ответ 5
Неверно, что строка заголовка включена другими заголовками. Сама строка заголовка включает только. Нет определений. Поэтому все необходимые определения, необходимые для использования строки, находятся в заголовках, включенных в строку заголовка. Эти заголовки могут быть уже включены в другие заголовки. Тогда все работает. Например, заголовок ios включает в себя stringbuf, который включает в себя...
Ответ 6
Даже если вы явно не включили строку, она была включена из-за другого стандартного заголовка, который вы включили. Например, вектор может содержать строку. Когда вы включаете вектор, каждая вещь из вектора будет включена в ваш файл.
Я думаю, что будущие версии Cpp должны иметь ключевое слово include_module или module; которые включают только определенный модуль из файла. Таким образом, если файл имеет 3 класса, мы включаем только тот, который нам нужен.
например
-I "../mingw/lib/include"
module <string>
Ищет в каталоге файлы, которые определяют класс строки. Компиляция будет значительно медленнее.