解读STL的编译错误提示

发表于:2007-05-26来源:作者:点击数: 标签:
使用stl的时候,如果发现编译出错,解读出错信息,对 程序员 来说,的确是个很大的考验。因为,错误隐藏在复杂的描述信息中。 使用stl 开发 程序,出错是难免的。如何有效的发现错误,然后纠正,才是关键。但是stl的出错信息实在是不高明,复杂的模版扩展开
使用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限制符,应该也行。不行反而是没有道理的。于是,动手修改程序,再试。

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的理解更加深刻了。

原文转自:http://www.ltesting.net