删除 '#include <algorithm>' 不会破坏代码

Posted

技术标签:

【中文标题】删除 \'#include <algorithm>\' 不会破坏代码【英文标题】:Removing '#include <algorithm>' doesn't break the code删除 '#include <algorithm>' 不会破坏代码 【发布时间】:2012-02-29 11:57:00 【问题描述】:

也许这是一个非常愚蠢的问题,但我正在阅读的书指示我编写一段代码,该代码使用算法对向量中的元素进行打乱和排序。为此,本书告诉我使用主 C++ 库中的算法库。好的,到目前为止我理解它,但是在编写代码之后,我想看看如果我从代码的顶部删除这个库会破坏什么,令我惊讶的是一切仍然有效。

这是我正在谈论的代码。当我从代码的顶部删除“#include 算法”时,没有任何问题。怎么会这样?不使用这个库时,'random_shuffle' 部分不应该中断吗?

#include <iostream>
#include <vector>
#include <algorithm>
#include <ctime>
#include <cstdlib>
using namespace std;

int main()

    vector<int>::const_iterator iter;

    cout << "Creating a list of scores.";
    vector<int> scores;
    scores.push_back(1500);
    scores.push_back(3500);
    scores.push_back(7500);

    cout << "\nHigh Scores:\n";
    for (iter = scores.begin(); iter != scores.end(); ++iter)
    
        cout << *iter << endl;
    

    cout << "\nFinding a score.";
    int score;
    cout << "\nEnter a score to find: ";
    cin >> score;
    iter = find(scores.begin(), scores.end(), score);
    if (iter != scores.end())
    
        cout << "Score found.\n";
    
    else
    
        cout << "Score not found.\n";
    

    cout << "\nRandomizing scores.";
    srand(static_cast<unsigned int>(time(0)));
    random_shuffle(scores.begin(), scores.end());
    cout << "\nHigh Scores:\n";
    for (iter = scores.begin(); iter != scores.end(); ++iter)
    
        cout << *iter << endl;
    

    cout << "\nSorting scores.";
    sort(scores.begin(), scores.end());
    cout << "\nHigh Scores:\n";
    for (iter = scores.begin(); iter != scores.end(); ++iter)
    
        cout << *iter << endl;
    

    system("pause");
    return 0;

【问题讨论】:

哪个编译器?如果我在 VS2010 中删除 #include &lt;algorithm&gt; 它将无法编译。 我使用的是 NetBeans IDE 7.1 和 MinGW。 【参考方案1】:

它起作用的原因是因为已包含在您还包含的标头中。

例如 vector 可能在其源代码中包含算法。这很常见,因为它们通常只是标题。

也就是说,您不能依赖标准库的特定实现在每个头文件中包含相同的内容。 (例如 with 可能适用于 MSVC,它可能会与 gcc stdlibc++ 中断)。

出于这个原因,我强烈建议包括您使用的内容,无论它在哪里编译。 --- 请注意,这与“您引用的内容”略有不同,因为标头中的点和引用的前向声明可以显着缩短构建时间。

【讨论】:

【参考方案2】:

C++ 标准没有规定每个标准头包含哪些头。这意味着,例如,&lt;vector&gt; 可能会在库实现 A 中使用 #include &lt;algorithm&gt;,但不会在库实现 B 中。这也可能在同一库的不同版本之间或在它的不同端口上发生变化。例如,glibc++ 曾经显着清理了它们的包含层次结构。

这让我们的 C++ 程序员感到有些不舒服,因为我们应该确保包含正确的那些,即使某些标准头文件已经这样做了;如果我们懒惰,我们就有可能在其他平台上编译中断,系统升级和降级。

经验法则:

根据标题的定义包括必要的内容。但仅此而已。

“但不是更多”,因为编译时间可能会变得不必要地慢。

【讨论】:

“我们冒着编译在其他平台上中断的风险” 或者当你写 apt-get upgrade gcc. @LightnessRacesinOrbit:这包含在我自己对“平台”一词的非常抽象和高度严格的定义中。升级后,它是另一个平台。但我会将其添加到我的答案中。 @phresnel:很公平。不同之处在于您应该每周升级(也许不是您的工具链,但您的环境通常需要更新安全等)但您不太可能经常切换部署平台(因此“另一个平台”变成了纯粹的可移植性问题)。【参考方案3】:

该代码有效,因为向量内部包含算法。 要验证包含哪些内容和不包含哪些内容,您可以通过将 -E 标志传递给编译器来生成预处理器输出。

编写一个示例文件:temp.C,它只有一行:

#include <vector>

现在,如果我们将文件编译为g++ -E temp.C,您将能够在输出中看到包含算法。

【讨论】:

对我表示赞成,但我认为虽然 g++ temp.cpp -M 包含算法(就像对我一样)更容易看到 请注意,这取决于库的实现;你不能依赖 &lt;vector&gt; 包括 &lt;algorithm&gt; 或其他任何东西(事实上,在我的特定实现中,它没有)。 带有 -E 标志的好建议,但是,它没有回答“这怎么可能?” 不错的一个。之前没用过-M【参考方案4】:

在这里休息

janus@Zeus:~$ g++ test.cpp 
test.cpp: In function ‘int main()’:
test.cpp:27:52: error: no matching function for call to ‘find(std::vector<int>::iterator, std::vector<int>::iterator, int&)’
test.cpp:27:52: note: candidate is:
/usr/include/c++/4.6/bits/streambuf_iterator.h:359:5: note: template<class _CharT2> typename __gnu_cxx::__enable_if<std::__is_char<_CharT2>::__value, std::istreambuf_iterator<_CharT2, std::char_traits<_CharT> > >::__type std::find(std::istreambuf_iterator<_CharT2, std::char_traits<_CharT> >, std::istreambuf_iterator<_CharT2, std::char_traits<_CharT> >, const _CharT2&)
test.cpp:39:48: error: ‘random_shuffle’ was not declared in this scope
test.cpp:47:38: error: ‘sort’ was not declared in this scope
janus@Zeus:~$

gcc 4.6.1

【讨论】:

不在这里,也许您使用的是不同的 IDE? 不是“怎么会这样?”的答案 @phresnel 如果假设不成立,那么回答它是怎么回事是没有意义的。也许 OP 使用了奇怪的编译器标志。我认为看到不同的编译器如何给他不同的结果可能会回答一些问题,例如它如何不受标头包含的标头标准的规定。【参考方案5】:

当我删除#include 算法行时,代码不会为我编译。冒着听起来很傲慢的风险,你确定你已经重新编译了吗?

我的编译器输出:

a.cpp(28) : error C3861: 'find': identifier not found
a.cpp(40) : error C3861: 'random_shuffle': identifier not found
a.cpp(48) : error C3861: 'sort': identifier not found

【讨论】:

我很确定。顺便说一句,我用的是NetBeans,也许是我们IDE的不同? 我只是在使用命令行。自从我使用 netbeans 已经有一段时间了,但我记得那时你必须右键单击项目浏览器中的类并单击重新编译。 (@phresnel:我认为这是一个礼貌的措辞可能的答案。他可能不知道需要重新编译的内容) 哎呀,我在一次意外中判断,我真的要发表我的评论了,对不起。【参考方案6】:

不幸的是,标准标头可以包含其他标准标头,因此无法保证如果您忘记某个标头,您的代码就会中断。

【讨论】:

【参考方案7】:

#include 预处理器指令不会在链接过程中“包含”库,只是指示预编译器读取头文件并将其作为单个单元包含在它正在编译的源文件中。

也就是说,algorithm 头文件可能被另一个包含文件包含。

注意:特定的函数或方法可以在头文件中声明和定义,因此不需要链接。

编辑: 您的代码写得很好,应该可以按预期工作。我只建议您使用换行符预定义字符 endl 并将其包含在输出序列的末尾,而不是在下一个序列的开头:

cout << "Creating a list of scores." << endl;  
cout << "High Scores:" << endl;

【讨论】:

以上是关于删除 '#include <algorithm>' 不会破坏代码的主要内容,如果未能解决你的问题,请参考以下文章

算法学习:图论

A1102 | 反转二叉树

图的遍历 | 1016 连通块块数

BZOJ4590 [Shoi2015]自动刷题机

bzoj 1103

CodeVS1743 反转卡片