【问题标题】:Why does omission of "#include <string>" only sometimes cause compilation failures?为什么省略“#include <string>”只是有时会导致编译失败?
【发布时间】:2012-03-02 20:05:10
【问题描述】:

我是 C++ 的初学者。当我写代码时,有时我写#include &lt;string&gt; 并且代码可以工作,有时我不写#include &lt;string&gt; 并且代码不工作。但有时它可以在没有#include &lt;string&gt; 的情况下工作。

所以我必须写#include &lt;string&gt; 以便代码有效吗?

【问题讨论】:

  • 人,到底是什么?!当然,这是一个真实、合理的问题!所有反对票和接近票来自哪里?回去睡觉吧。
  • 不知何故,在我看来,这个问题和these are not the droids you are looking for一样有效。
  • 这个问题本来可以更好地提出,但是当他们以“我是 C++ 的初学者”开始时,可​​以肯定地假设他们可能并不完全理解包含的工作并留下评论而不是关闭或否决票。

标签: c++ string include


【解决方案1】:

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

some 平台上的

Some 编译器可能在每月的某些 时间编译,即使您未能包含标头。这种行为是不幸的、不可靠的,并不意味着您不应该包含标题。

原因很简单,您添加了其他标准标题恰好包含string。但正如我所说,这通常是不可靠的,它也可能会突然发生变化(例如,当安装了新版本的编译器时)。

始终包含所有必要的标题。不幸的是,似乎没有可靠的在线文档说明需要包含哪些标题。请查阅一本书或官方 C++ 标准。

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

#include <iostream>

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

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

【讨论】:

  • 知道&lt;string&gt;以外的头文件是否会发生这种情况吗?
  • @C.R.显然,它确实如此,因为标准标题有时会相互使用。例如,std::pair&lt;utility&gt; 中定义,但标准库的 no 实现要求您在已经包含 &lt;map&gt; 的情况下包含此标头,因为后者需要 @987654330 @。其他类型也是如此。顺便说一句,与适当的模块系统相比,这是 C++ 头文件系统的一大弱点。
  • 关于 不幸的是,似乎没有可靠的在线文档说明需要包含哪些标头。您可以随时在 cppreference.com 上搜索您使用的内容和它会告诉你它所在的标题。
  • @NathanOliver 是的,他们现在严格记录了这一点。以前的版本没有。 cppreference.com 现在是我的 #1 首选参考。
【解决方案2】:

确实包含的其他标头中可能包含#include &lt;string&gt;

尽管如此,如果这些“其他”标头发生更改 - 例如由于不同(或不同版本)编译器/标准库实现、平台甚至只是构建配置。

(当然,这个讨论适用于任何标题,而不仅仅是&lt;string&gt;。)

【讨论】:

    【解决方案3】:

    虽然在特定的源文件中没有直接出现#include &lt;string&gt;,但这并不意味着它没有被另一个头文件包含。考虑一下:

    文件: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";
    }
    

    【讨论】:

      【解决方案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>
          

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

          【讨论】:

            【解决方案7】:

            正如布兰科所说:

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

            我们来看看iostream包括:

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

            如果您查看istream,您可以看到一些include 像这样,我们有:

            iostream => istream => ios => iosfwd

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

            #include // 用于字符串前向声明。

            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 &lt;string&gt;

            【讨论】:

              猜你喜欢
              • 2012-03-21
              • 2018-04-08
              • 1970-01-01
              • 2021-10-07
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2020-12-11
              相关资源
              最近更新 更多