| 使用stl的时候,如果发现编译出错,解读出错信息,对程序员来说,的确是个很大的考验。因为,错误隐藏在复杂的描述信息中。 使用stl开发程序,出错是难免的。如何有效的发现错误,然后纠正,才是关键。但是stl的出错信息实在是不高明,复杂的模版扩展开来之后,一看就头晕。下面举个例子,不是教人怎么看,只是就事论事。 先看程序: wostream & operator<< (wostream &out, const table &t) { typedef list<row> lr; typedef lr::const_iterator rowi; rowi ir; ir=t.c.begin(); //<-------------编译会出错. table p(t); ir=p.c.begin(); cout<<"table t:"<<t.c.size()<<endl; cout<<"table:"<<p.c.size()<<endl; out<<*ir<<endl; return out; } 如果这么写,编译出错信息是: Error 226: "table.cpp", line 49 # No appropriate function found for call of 'operator ='. Last viable candidate was "std::__rw_list_iter<row,long,row *,row &> &std::__rw_list_iter<row,long,row *,row &>::operator =(const std::__rw_list_iter<row,long,row *,row &> &)" ["/opt/aCC/include_std/list", line 72]. Argument of type 'class __rw_list_iter<row,long,const row *,const row &>' could not be converted to 'const std::__rw_list_iter<row,long,row *,row &> &'. ir=t.c.begin(); ^^^^^^^^^^^^^^ *** 错误退出代码 2 一开始,这段提示完全看不懂,根本不知道什么错.虽然全是英语,但是无法理解.之后尝试了很多方法,比如说再建立一个table变量,由它复制参数t,然后由这个中间变量取出iterator。 很明显,这样的做法,开销太大。我相信,stl里肯定有简单的解决方案,只是我还不知道。 上论坛,看书,兜了一大圈,终于开了壳。当然灵感还是来自于错误提示。 Argument of type 'class __rw_list_iter<row,long,const row *,const row &>' could not be converted to 'const std::__rw_list_iter< row,long, row *, row &> &'. 上面这句话很关键,意思就是说两个对象,数据类型不一样,无法转换。而且是前者无法转为后者。前者里面有const,很明显是我传入的参数。因为不希望传入的参数被改动,因此用了const来限定它。 后面的肯定是我在函数体中定义的iterator,这是个普通的iterator,可以修改对象的。两个产生了矛盾,问题应该出在这里。 解决的方法似乎很简单,把传入参数的const去掉即可。 于是我试了试,编译还是出错。这次我没细看,以为还是不行,于是继续研究。 经过一天的时间,晚上和白天都在思考这个问题,终于能够把我看到的一鳞半爪的知识连贯起来想想了。如果const 不能去掉,我应该可以用const iterator来接受参数t中的iterator啊。实际上,我也是今天白天才看到有const_iterator这么一个东西。 于是修改函数为下面形式: wostream & operator<< (wostream &out, const table &t) { typedef list<row> lr; typedef lr::const_iterator rowi; rowi ir; ir=t.c.begin(); cout<<"table t:"<<t.c.size()<<endl; out<<*ir<<endl; return out; }
这样处理很快就搞定了。 :-) 果然很简单,但是没人告诉你,你就是不知道。 在写这篇帖子的时候,自己的思路也慢慢清晰起来。回头再看看当时的想法,去掉参数中的const限制符,应该也行。不行反而是没有道理的。于是,动手修改程序,再试。 wostream & operator<< (wostream &out, table &t) { typedef list<row> lr; typedef lr::iterator rowi; rowi ir; ir=t.c.begin(); cout<<"table t:"<<t.c.size()<<endl; out<<*ir<<endl; return out; } 还是出错,但是看错误提示,问题好象出在我的测试程序中。
ld: Unsatisfied symbol "operator <<(std::basic_ostream<wchar_t,std::char_traits< wchar_t>> &,const table &)" in file test.o 1 errors.
仔细看看这里的提示,发现test.o里面对于重载的操作符的格式还是老样子,居然没有变化。想想原因,估计是以前编译好的信息存放在test.o中。因为test.cpp文件一直没有变过,而我又是用make来做,所以test.o也没有更新。那么删除test.o,重新编译一下吧。 这次果然也成功了。两种方法,效果是一样的。当然从安全性来考虑,用const_iterator会更安全一些。 经过这次的学习,对stl的理解更加深刻了。 |