为什么省略“#include < string>”有时只会导致编译失败?

Why does omission of "#include <string>" only sometimes cause compilation failures?

提问人:user1245895 提问时间:3/3/2012 最后编辑:Rob Kennedyuser1245895 更新时间:8/23/2020 访问量:5530

问:

我是 C++ 的初学者。当我写代码时,有时我写,代码工作,有时我不写,代码不工作。但有时它可以在没有.#include <string>#include <string>#include <string>

那么我必须编写代码才能正常工作吗?#include <string>

C++ 字符串 包括

评论

24赞 Konrad Rudolph 3/3/2012
人,什么鬼?!当然,这是一个真实、合理的问题!所有的反对票和接近票从何而来?回去睡觉吧。
0赞 karlphillip 3/3/2012
不知何故,在我看来,这个问题和.these are not the droids you are looking for
3赞 AJG85 3/3/2012
这个问题本来可以提出得更好,但是当他们以“我是 C++ 初学者”开头时,可以肯定的是,他们可能并不完全理解如何包括工作并发表评论而不是关闭或反对投票。

答:

40赞 Konrad Rudolph 3/3/2012 #1

如果使用在标准标头中声明的成员,则可以,必须直接或间接(通过其他标头)包含该标头。string

某些平台上的某些编译器可能会在每月的某个时间进行编译,即使您未能包含标头也是如此。这种行为是不幸的、不可靠的,并不意味着你不应该包含标题。

原因很简单,您已经包含了其他标准标头,这些标头恰好包括 .但正如我所说,这通常不能被依赖,它也可能非常突然地改变(例如,当安装了新版本的编译器时)。string

始终包含所有必要的标头。不幸的是,似乎没有关于需要包含哪些标头的可靠在线文档。查阅书籍或官方 C++ 标准。

例如,以下代码使用我的编译器 ( 4.6) 进行编译:gcc

#include <iostream>

int main() {
    std::string str;
}

但是,如果我删除第一行,即使标题实际上应该是不相关的,它也不会再编译。iostream

评论

0赞 Siyuan Ren 3/9/2013
知道它是否发生在头文件上吗?<string>
4赞 Konrad Rudolph 3/9/2013
@C.R.显然,它确实如此,因为标准标头有时会相互使用。例如,定义在 但标准库没有实现,如果您已经包含此标头,则要求您包含此标头,因为后者需要 .其他类型也是如此。顺便说一下,与适当的模块系统相比,这是 C++ 头系统的一大弱点。std::pair<utility><map>std::pair
8赞 NathanOliver 7/19/2016
关于 不幸的是,似乎没有关于需要包含哪些标题的可靠在线文档。 您可以随时在 cppreference.com 上搜索您正在使用的内容,它会告诉您它所在的标题。
2赞 Konrad Rudolph 7/19/2016
@NathanOliver 是的,他们现在严格记录了这一点。以前的版本没有。cppreference.com 现在是我的#1首选参考。
0赞 cooky451 3/3/2012 #2

如果只是使用指向用户定义类型的指针/引用,则只需声明该类型:

class my_class;
void foo(const my_class& c);

但是,当您使用该值时,编译器需要知道大小以及类型的定义。

请记住,标准标头可能包含其他标头,这并不意味着所有实现都会自动执行此操作,因此您不能依赖它。

5赞 Branko Dimitrijevic 3/3/2012 #3

包含的其他标头可能包含在其中。#include <string>

尽管如此,通常最好直接在代码中加入,即使对于成功构建不是绝对必要的,以防这些“其他”标头发生变化 - 例如,由于不同(或不同版本)的编译器/标准库实现、平台甚至只是构建配置。#include <string>

(当然,此讨论适用于任何标头,而不仅仅是<字符串>

3赞 Linus Kleen 3/3/2012 #4

虽然在特定的源文件中没有直接出现,但这并不意味着它没有被另一个头文件包含。考虑一下:#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's a #include <string> in header.h
    string s = "Bar";
}

文件:source3.cc

void zoid()
{
    // Here's the error; no such thing as "string", since non of the
    // previous headers had been included.
    string s = "Zoid";
}
0赞 F. Kaspar 1/15/2014 #5

标头字符串不包含在其他标头中。标头字符串本身只有 includes。没有定义。因此,使用字符串所需的所有必要定义都在标头字符串包含的标头中。这些标头可能已被其他标头包含。然后一切正常。例如,标头 ios 包括 stringbuf,其中包括 ...

0赞 user9599745 4/26/2019 #6

即使您没有显式包含字符串,它也已包含在内,因为您包含了另一个标准标头。例如,vector 可能包含字符串。当您包含 vector 时,vector 中的所有内容都将包含在您的文件中。

我认为 Cpp 的未来版本应该有一个 include_module 或 module 关键字;其中仅包含文件中的特定模块。因此,如果一个文件有 3 个类,我们只包含我们需要的类。

例如
-I “../mingw/lib/include”

 module <string>

在目录中搜索定义字符串类的文件。编译速度会明显变慢。

0赞 Mehdi Mostafavi 8/23/2020 #7

正如布兰科所说:

您包含的其他标头中可能包含 #include。

让我们来看看包括:iostream

#include <bits/c++config.h>
#include <ostream>
#include <istream>

如果你检查你可以看到一些这样的,我们有:istreaminclude

iostream => istream => ios => iosfwd

在我们有字符串库!但这不是标准的,它是用于正向声明的。我们有:iosfwdiosfwd

#include < bits/stringfwd.h> // 用于字符串转发声明。

和在:stringfwd.h

@file bits/stringfwd.h
This is an internal header file, included by other library headers.
Do not attempt to use it directly. @headername{string}

所以,你可以在没有.string#include <string>