Effective STL 条款6 : 当心C++另人迷惑的解析

原创 2004年07月23日 16:14:00

条款6: 当心C++另人迷惑的解析<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

 

假如你有一个整数构成的文件,需要把它复制到一个list.以下代码看起来是一个很有意义的方法:

 

ifstream dataFile("ints.dat");

list data(istream_iterator(dataFile), // warning! this doesn't do

               istream_iterator());        // what you think it does

 

 

这里的想法是传递一对istream_iteratorlist的区间构造函数(Item5),来将文件中的整数

拷贝到列表中.

 

这段代码能通过编译,但在运行期,它不做任何事情.它不会从文件中读取任何数据.它也不创建列表.

因为第二条语句并没有声明一个list,也没有调用构造函数.它做了什么呢?..它做的事情是如此古怪.

以至我不敢直接告诉你,你不会相信。我只能一点点的解释。你坐好了吗?如果没有你应该找一把椅子。

 

我们从最基础的开始。这一行代码声明了一个函数f,它具有一个double类型的参数,返回一个int类型的值。

 

Int f(double d);

 

下面一行起到相同的作用。参数d两边的括号是多余的,将被忽略。

 

Int f(double (d));      //same as above; parens around d are ignored

 

底下这行代码声明同一个函数。它没有漏掉了参数名。

 

Int f(double);        //same as above; parameter name is omitted.

 

你也许对以上三个声明形式很熟悉。尽管将参数名放在括号内的能力很新鲜。(很久以前它对我来说也行新鲜)

再多看三个函数声明。第一个声明了一个具有函数指针参数的函数。这个函数指针指向一个无参并返回double类型的函数。

 

Int g(double (*pf)());   //g takes a pointer to a function as a parameter

 

这有另一个方法。唯一不同之处是pf使用了非指针语法(在CC++中都有效)

 

int g(double pf());    //same as above; pf is implicitly a pointer;

 

与平时一样,参数名可以省略。因些这是第三种声明g的方法,消去名称pf

 

Int g(double ());     //same as above, parameter name is omitted

 

注意括号在参数名称上(比如f的第二个声明中的d)和只有括号(这个例子中)的情况。在参数名上的括号会被忽略,但只有括号表示存在一个参数列表:它们表示出现在这里的参数是一个指向函数的指针。

fg的声明热身后,可以来看看开头的代码了。再次列在这里:

 

list data(istream_iterator(dataFile), istream_iterator());

 

打起精神来,这行代码声明了一个函数,名为data,其返回类型是list。函数data有两个参数:

第一个参数名为dataFile。它的类型是istream_iterator。在dataFile两侧的括号被忽略。

第二个参数没有名字。它的类型是指向函数的指针,指向的函数类型为无参,返回值类型是istream_iterator

 

吃惊吗?但是它说明了一个C++的通用规则,将尽可能多的东西可以被解析为函数声明。如果你使用过一段时间的C++,你肯定碰到过这条规则的其它宣告形式。你多少次发现过这种错误呢?

class Widget {...}; // assume Widget has a default constructor

Widget w();      //'uh oh...

这并未声明一个名为wWidget,它声明了一个名为w无参函数,其返回值为一个Widget。学习并认识这一点就像通过了真正C++程序员的仪式。

这些都很有趣(在它曲折的形式上),但是它不能帮助我们声明我们希望得到的东西:定义一个list对象由文件的内容初始化。现在我们知道如何防止它被解析,这很容易表示。C++不许将形参声明放在括号之内,但函数调用的参数却可以带上括号。因些加上一对括号可以强制编译器用我们的方式读代码。

list data((istream_iterator(dataFile)),  // note new parens

istream_iterator0);                      // around first argument

// to list's constructor

这种形式声明data,使用istream_iterator工具定义一组区间,使用区间构造函数。(再一次,参见条款5),它很值得这样做。

不幸,并不是所有编译器知道这一点。我测试过一些编译器,有一半拒绝data的声明(正确形式),除非使用没有附加括号的不正确形式。

(原文在此:Of the several I tested, almost half refused to accept data's declaration unless it was incorrectly declared without the additional parentheses!

为了安抚这些编译器,你只有闭上眼睛,使用我痛苦的说明为错误的声明方式。但是这是不可移植的,同时也是短视的。最后,现在解析错误的编译器未来总会更正,对吗?(当然)

最好的解决方案是在data声明中不使用流行的匿名istream_iterator对象,简单地给出这些迭代器的名字。以下代码在任何地方都可以工作:

ifstream dataFile(" ints.dat"};

istream_iterator dataBegin(dataFile);

istream_iterator dataEnd;

list data(dataBegin. dataEnd);

这段代码与通用的STL风格不同,它使用了命名的迭代器对象,但是你需要决定使用对于编译器和程序员看来都有岐意的代码是否值得。

《Effective C++》设计与声明:条款18-条款19

这两个条款讲的是:接口的设计和类的设计。其中接口的设计原则是让接口容易被正确使用,不容易被误用;后面有一系列的做法。类的设计,讲的是类设计犹如新类型type的设计。在设计类时要考虑的一系列问题。...
  • KangRoger
  • KangRoger
  • 2015年01月21日 21:43
  • 1326

effective stl 第19条:理解相等(equality)和等价(equivalence)的区别

#include #include #includeusing namespace std;bool ciStringCompare(const string l, const string r) {...
  • u014110320
  • u014110320
  • 2016年09月20日 23:36
  • 238

《Effective C++》学习笔记——条款31

《Effective C++》学习笔记——条款31:将文件间的编译依存关系降至最低
  • lx417147512
  • lx417147512
  • 2015年06月15日 13:51
  • 1368

《Effective C++》学习笔记——条款25

《Effective C++》学习笔记——条款25:考虑写出一个不抛异常的 swap 函数
  • lx417147512
  • lx417147512
  • 2014年12月30日 22:32
  • 837

《Effective C++》:条款41-条款42

条款41了解隐式接口和编译期多态 条款42了解typename的双重意义条款
  • KangRoger
  • KangRoger
  • 2015年03月10日 22:13
  • 1204

《Effective C++》:条款28-条款29

条款28避免返回handles指向对象内部成分:指的是不能返回对象内部数据/函数的引用、指针等。 条款29为异常安全而努力是值得的:指的是要有异常处理机制,避免发生异常时造成资源泄露等问题。...
  • KangRoger
  • KangRoger
  • 2015年02月19日 19:47
  • 1372

《Effective C++》让自己习惯C++:条款1-条款4

《Effective C++》条款1到条款4。基本是总结C++的一些特点,尤其是不同于C语言的特点。...
  • KangRoger
  • KangRoger
  • 2014年12月13日 19:26
  • 2353

《Effective C++》资源管理:条款13-条款15

在系统中,资源是有限的,一旦用完必须归还给系统,否则可能会造成资源耗尽或其他问题。例如,动态分配的内存如果用完不释放会造成内存泄漏。 这里说的资源不仅仅是指内存,还包括其他,例如文件描述符、网络连接、...
  • KangRoger
  • KangRoger
  • 2015年01月14日 21:46
  • 1285

《Effective C++》:条款44-条款45

条款44将与参数无关的代码抽离templates 条款45运用成员函数模板接受所有兼容类型...
  • KangRoger
  • KangRoger
  • 2015年03月12日 22:01
  • 1484

Effective Modern C++ 条款28 理解引用折叠

Effective Modern C++ 条款28
  • big_yellow_duck
  • big_yellow_duck
  • 2016年09月04日 19:34
  • 1993
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Effective STL 条款6 : 当心C++另人迷惑的解析
举报原因:
原因补充:

(最多只允许输入30个字)