2011年2月21日

重学C++之01《Essential C++》:P5程序的#include 注释与否

----------------------------------------------
#include <iostream>
#include <string>

using namespace std;

int main()
{
    string user_name;
    cout << "Please enter your first name: ";
    cin >> user_name;
    cout << '\n'
         << "Hello, "
         << user_name
         << " ... and goodbye! \n";
    return 0;
}
----------------------------------------------
上面这段程序在Ubuntu 10.04上g++编译没问题,执行也没问题。按照P6页底的练习1.2将第二行注释掉,g++编译没问题,执行也没问题。

本来想忽略掉练习题直接往下看的,刚才等待某程序执行的过程中,一时兴致,将这个练习作了一下。这个有点超出我的想象了。为什么不引用<string>也可以呢。遍访google的结果,找到了大致的原因如下:

----------------------------------------------------------
以前也有同事遇到一样的问题,好的习惯是使用时包含string头。iostream间接引用了string,在VC下的确会出现操作符不能使用的情况,我觉得这个做法是正确的,g++使用的STL实现可以在只包含iostream头时照样使用那些操作符。
----------------------------------------------------------
参见:http://topic.csdn.net/t/20051213/12/4456074.html


有人专研的很深:
----------------------------------------------------------
我找到了原因。

在<iostream>中的“stringbuf”类使用到了string定义它的一个public member.

class stringbuf{
public:
string str ( ) const;
void str ( const string & s );
...
}

所以<iostream>应该要包含<string>才可以完成这个声明。

感谢各位。
----------------------------------------------------------
参见:http://topic.csdn.net/u/20100121/05/7abe6594-5ad2-4f1e-b1f8-8c9f74c3bc59.html


有人还引用《Effective C++》来说明类似问题的解决方案:
----------------------------------------------------------
《Effective   STL》

条款48:总是#include适当的头文件

STL编程的次要麻烦之一是虽然可以很容易地建立可以在一个平台上编译的软件,但在其它平台上则需要附加的#include指示。这个烦恼来自一个事实:C++标准(不像C标准)未能指定哪一个标准头文件必须或者可能被其他标准头文件#include。由于有了这样的灵活性,不同的实现就会选择去做不同的东西。

这在实践中意味着什么?我可以给你一些的概念。我使用了五个STL平台(咱们叫它们A、B、C、D和E),花了一些时间在它们上测试了一些小程序来看看我可以在忽略哪个标准头文件的情况下仍然成功编译。这间接地告诉我哪个头文件#include了其他的。这是我所发现的:

        *   对于A和C, <vector>   #includes   <string> .
        *   对于C, <algorithm>   #includes   <string> .
        *   对于C和D,   <iostream>   #includes   <iterator> .
        *   对于D,   <iostream>   #includes   <string>   and   <vector> .
        *   对于D和E,   <string>   #includes   <algorithm> .
        *   对于所有的五个实现, <set>   #includes   <functional> .

除了 <set>   #include   <functional> 外,我无法使缺少头文件的程序通过实现B。按照Murphy定律,你总是会在像A、C、D或E那样的平台上开发,然后移植到像B那样的平台,尤其是当移植的压力很大而且完成的时间很紧的情况下。

但是请别指责你将要移植的编译器或库实现。如果你缺少了需要的头文件,这就是你的过错。无论何时你引用了std名字空间里的元素,你就应该对   #include合适的头文件负责。如果你遗漏了它们,你的代码也可能编译,但你仍然缺少了必要的头文件,而其他STL平台可能正好会抵制你的代码。

要帮你记起需要的东西,关于在每个标准STL相关的头文件中都有什么,这里有一个快速概要:

        *   几乎所有的容器都在同名的头文件里,比如,vector在 <vector> 中声明,list在 <   list> 中声明等。例外的是 <set> 和 <map> 。 <set> 声明了set和multiset, <   map> 声明了map和multimap。
        *   除了四个算法外,所有的算法都在 <algorithm> 中声明。例外的是accumulate(参见条款37)、inner_product、adjacent_difference和 partial_sum。这些算法在 <numeric> 中声明。
        *   特殊的迭代器,包括istream_iterators和istreambuf_iterators(参见条款29),在 <iterator> 中声明。
        *   标准仿函数(比如less <T> )和仿函数适配器(比如not1、bind2nd)在 <functional> 中声明。

无论何时你使用了一个头文件中的任意组件,就要确定提供了相应的#include指示,就算你的开发平台允许你不用它也能通过编译。当你发现移植到一个不同的平台时这么做可以减少压力,你的勤奋将因而得到回报。
----------------------------------------------------------
参见:http://topic.csdn.net/t/20051213/12/4456074.html

没有评论: