使用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限制符,应该也行。不行反而是没有道理的。于是,动手修改程序,再试。
clearcase/" target="_blank" >cc33ff">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的理解更加深刻了。