c++ 学习错误列表

c++ 学习错误列表

这是学习和使用c++语言过程中,出现的错误及解决方法列表,随着学习和实践深入,此列表将不断更新。


No.1:prog4.cpp(8) : error C2440: “初始化”: 无法从“const int”转换为“int &”

        转换丢失限定符

  1. #include <iostream>  
  2. int main()  
  3. {  
  4.     const int iSize = 1024;  
  5.     int iCnt = 0;  
  6.     const int &iRefval = iSize;//ok  
  7.     int &iRef = iSize;//不允许非const引用绑定到const对象  
  8.     const int &icRef = iCnt;//const引用可以绑定到右值  
  9.     std::cout<<"iRefval:  "<<iRefval<<std::endl;  
  10.     std::cout<<"icRef:    "<<icRef<<std::endl;  
  11.     return 0;  
  12. }  

解决办法:  非const引用绑定到const对象,如果允许的话,那么可以通过非const引用修改const原对象,这个出现一个矛盾,因此c++不允许执行此操作。解决方法就是使用非const引用绑定到同类型的非const对象,使用const引用绑定到不同但相关的类型的对象或者右值。


No.2: prog2.cpp(8) : error C2664: '__thiscall std::list<int,class std::allocator<int> >::std::list<int,class std::allocator<int> >(unsigned int,const int &, const class std::allocator<int> &)' : cannot convert parameter 1 from 'class std::deque<int,class std::allocator<int> >::iterator' to 'unsigned int'   No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called

  1. //prog2.cpp  
  2. #include <iostream>  
  3. #include <list>  
  4. #include <deque>  
  5. using namespace std;  
  6. void main()  
  7. {       
  8.      //Define a list that holds elements that are deques that hold ints  
  9.      deque<int>   ideque(10,1);  
  10.      list<int>  ilist(ideque.begin(),ideque.end());  
  11.      for(list<int>::const_iterator itbegin=ilist.begin(),itend=ilist.end();itbegin!=itend;++itbegin)  
  12.          cout<<*itbegin<<endl;  
  13. }  

 

解决方法:vc 6.0对模板库支持不够好,使用vs2010编译通过。

No.3 TextQuery.cpp(63) : warning C4172: returning address of local variable or temporary

[html]  view plain copy print ?
  1. //返回单词出现的行号set  
  2. const set<int> & TextQuery::RunQuery(string word) const  
  3. {       
  4.       map< string,set<int> >::const_iterator it = m_mapWordLine.find(word);  
  5.       if(it != m_mapWordLine.end())  
  6.         return it->second;  
  7.       else  
  8.         return set<int>();//emptyset  
  9. }  


 

解决方法:愿意是返回set对象的const引用以减轻复制set对象的负担,但是这里返回空的set对象的局部引用是错误的,c++ primer 原文采用的方法是返回set对象,不使用引用,这也是一种解决方法。另外使用std::vector<std::string>::size_type  比int型的set好。

 

No.4 printchar.cpp(13) : error C2440: 'initializing' : cannot convert from 'char *' to 'const class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *'

        Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast

[html]  view plain copy print ?
  1. //输出一行中所有字符  
  2. void printchar(string &line)  
  3. {  
  4.     istringstream iss(line);  
  5.     string word;  
  6.     while(iss>>word)  
  7.         for(vector<string>::const_iterator itbegin=word.begin(),itend=word.end();itbegin != itend; ++itbegin)  
  8.             cout<<*itbegin<<endl;  
  9. }  

解决方法:标准库string对象可以使用迭代器操作 ,但是其迭代器要正确使用,应该使用string::const_iterator 后者使用下标操作来获取string对象中的字符。

No.5 fatal error  "vector iterator + offset out of range" "standard C++ libraries out of range "

代码如下:

  1. #include <iostream>  
  2. #include <iterator>//使用back_inserter   
  3. #include <algorithm>  
  4. #include <vector>  
  5. using namespace std;  
  6. void main()  
  7. {       
  8.      vector<int> ivec;  
  9.      try  
  10.      {     
  11.         fill_n(ivec.begin(),10,1);//error  should use fill_n (back_inserter(ivec), 10, 1);   
  12.         for(vector<int>::iterator itbegin=ivec.begin(),itend=ivec.end();itbegin!=itend;++itbegin)  
  13.             cout<<*itbegin<<endl;  
  14.      }  
  15.      catch (runtime_error err)  
  16.      {    
  17.         cerr << "Error: "<<err.what()<<endl;  
  18.      }  
  19.      catch(out_of_range or)  
  20.      {  
  21.          cerr << "Error: "<<or.what()<<endl;  
  22.      }  
  23.      catch(exception ex)  
  24.      {  
  25.         cerr << "Error: "<<ex.what()<<endl;  
  26.      }  
  27.         
  28. }  

解决方法:fill_n()函数将在vector中从头开始,将指定个数的元素设置为给定的值。fill_n函数假定对指定数量的元素做写操作是安全的。初学者常犯的错误的是:在没有元素的空容器上调用 fill_n 函数,因此需要使用back_inserter ,这种插入迭代器。当使用插入迭代器赋值时,则会在容器中添加一个新元素,其值等于赋值运算的右操作数的值。因此需将代码改为:

fill_n (back_inserter(ivec), 10, 1);

No.6  prog7.cpp(8) : error C2780'void __cdecl std::sort(_RI,_RI,_Pr)' : expects 3 arguments - 2 provided

C:\Program Files\Microsoft Visual Studio\VC98\include\algorithm(588) : see declaration of 'sort'
prog7.cpp(8) : error C2782: 'void __cdecl std::sort(_RI,_RI)' : template parameter '_RI' is ambiguous
could be 'class std::reverse_iterator<int *,int,int &,int *,int>' or 'int *'

代码如下:

  1. #include <iostream>  
  2. #include <algorithm>  
  3. #include <vector>  
  4. using namespace std;  
  5. void main()  
  6. {       
  7.      vector<int> ivec1(10,1);  
  8.      sort(ivec1.begin(), ivec1.rend());//类型不匹配的错误 可以在编译时检查出来  
  9. }  

解决方法:

sort函数重载有两个版本,所以出现上面的错误提示,无论哪个版本,要求给定一对迭代器范围,而在标准库中,有输入范围的泛型算法要求其两个迭代器类型完全一样,包括const属性。要么都是const,要么都是非const,否则无法通过编译。

上述的begin函数返回是普通迭代器,而rend函数返回的是反向迭代器,因此两个实参类型不匹配,出现了上述错误,解决方法就是正确的传递实参,使用类型完全一样的迭代器标记范围。

No.7  ..\sales_item\sales_item.h(24) :error C2804:binary 'operator +' has too many parameters

代码如下:

  1. // header file Sales_item.h  
  2. #include <iostream>  
  3. #include <string>  
  4. class Sales_item   
  5. {     
  6.     // private members   
  7.     private:  
  8.     std::string isbn;  
  9.      unsigned units_sold;  
  10.     double revenue;  
  11.     //public method  
  12.     public:  
  13.     ..  
  14.      //Overloaded Operator as member function     
  15.     Sales_item& operator+=(const Sales_item&);//Compound Assignment Operators  
  16.     Sales_item operator+(const Sales_item& lhs, const Sales_item& rhs);  
  17. };  
  18. // implement file  Sales_item.cpp  
  19. using std::istream;    
  20. using std::ostream;  
  21. //Overloaded Operator as nonmember functions  
  22. inline Sales_item Sales_item::operator+(const Sales_item& lhs, const Sales_item& rhs)  
  23. {  
  24.       Sales_item ret(lhs);  // copy lhs into a local object that we'll return  
  25.                   ret += rhs;           // add in the contents of rhs  
  26.                 return ret; // return ret by value ,not by reference  
  27. }  


 

解决方法:+操作符包括两个操作数,应该重载为普通非成员函数。

注意重载操作符的形参数目(包括成员函数的隐式 this 指针)与操作符的操作数数目相同。对称的操作符,如算术操作符、相等操作符、关系操作符和位操作符,最好定义为普通非成员函数。因此+应该重载为普通非成员函数。这里重载为成员函数时多了一个this形参,故对于+操作符来说,出现参数过多的错误。

即书写为:

  1. // header file  
  2. Sales_item operator+(const Sales_item& lhs, const Sales_item& rhs);  
  3. //implement file  
  4. //Overloaded Operator as nonmember functions  
  5. inline Sales_item operator+(const Sales_item& lhs, const Sales_item& rhs)  
  6. {  
  7.       Sales_item ret(lhs);  // copy lhs into a local object that we'll return  
  8.       ret += rhs;           // add in the contents of rhs  
  9.       return ret; // return ret by value ,not by reference  
  10. }  


 

No.8  Compiling...main.cppLinking...main.obj :error LNK2001: unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char> > &__cdecloperator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class Sales_item const &)"(??6@YAAAV?$basic_ostream@DU$char_traits@D@std@@@std@@AAV01@ABVSales_item@@@Z)

....(省略后续同类错误)

Sales_item.exe - 4 error(s), 0 warning(s)

错误原因之一,在于将inline函数的实现放在了单独的实现文件中了,解决方法:

将inline函数的实现放置在头文件中。具体请参考:《类的内联函数的实现应该放在哪里》一文。

 

N0.9 conflict.cpp(7) : error C2872: “count”: 不明确的符号

可能是“conflict.cpp(4) : int count”
或 “C:\Program Files\Microsoft Visual Studio 11.0\VC\INCLUDE\xutility(3251) : iterato
r_traits<_Iter>::difference_type std::count(_InIt,_InIt,const _Ty &)”
conflict.cpp(12) : error C2872: “count”: 不明确的符号
可能是“conflict.cpp(4) : int count”
或 “C:\Program Files\Microsoft Visual Studio 11.0\VC\INCLUDE\xutility(3251) : iterato
r_traits<_Iter>::difference_type std::count(_InIt,_InIt,const _Ty &)”
出错代码

  1. #include <iostream>  
  2. using namespace std;  
  3.   
  4. int count = 0;  
  5. int increment()  
  6. {  
  7.     return ++count;// error, identifier count is ambiguous  
  8. }  
  9. int main()  
  10. {     
  11.     increment();  
  12.     cout<<"count= "<<count<<endl;  
  13.     return 0;  
  14. }  
解决办法:  使用命名机制来避免命名冲突,这里count既可以是程序中全局变量count,也可能是std::count,因此引起歧义,导致出错。解决方法:

1)尽量少用directive方式来引用命名空间:(directive方式即using namespace std;)

取而代之,使用use std::cout,引用命名空间的成员,而不是将其置为后续名字的默认命名空间。

  1. #include <iostream>  
  2.   
  3. using std::cout;//使用命名空间一个名字  
  4. using std::endl;  
  5.   
  6. int count = 0;  
  7. int increment()  
  8. {  
  9.     return ++count;  
  10. }  
  11. int main()  
  12. {     
  13.     increment();  
  14.     cout<<"count= "<<count<<endl;  
  15.     return 0;  
  16. }  

2)使用命名空间引用变量,在命名空间中定义变量、函数和类。

  1. #include <iostream>  
  2. using namespace std;  
  3.   
  4. namespace global {  
  5.     int count = 0;//重新定义一个命名空间  
  6. }  
  7. int increment()  
  8. {  
  9.     return ++global::count;  
  10. }  
  11. int main()  
  12. {     
  13.     increment();  
  14.     cout<<"count= "<<global::count<<endl;  
  15.     return 0;  
  16. }  

No.10  error C2664: “find_char”: 不能将参数 1 从“const char [14]”转换为“std::string &


出错代码:

  1. #include <iostream>  
  2. #include <string>  
  3. using std::cout;  
  4. using std::endl;  
  5. using std::string;  
  6. //const引用形参举例  
  7. //非const引用形参只能与完全同类型的非const对象关联  
  8. std::size_t find_char(string &s,char c)  
  9. {  
  10.    string::size_type i = 0;  
  11.    while(i != s.size() && s[i] != c)  
  12.        ++i;  
  13.    if(i == s.size())  
  14.        return string::npos;  
  15.    else  
  16.        return i;  
  17. }  
  18. int main(int argc, char *argv[])  
  19. {     
  20.     //字面值常量为const对象,调用出错  
  21.     if(find_char("Hello, world.",'.') != string::npos)  
  22.     {  
  23.         cout<<"a sentence."<<endl;  
  24.     }  
  25.     return 0;  
  26. }  

解决方法: 如果函数不修改相应实参,应该将引用形参定义为const引用,这样字面值常量、const对象也能调用此函数,避免不必要的限制。

No.11  error C2512: “Foo”: 没有合适的默认构造函数可用

错误信息如下:

C:\Program Files\Microsoft Visual Studio 11.0\VC\INCLUDE\xmemory0(601) : error C2512: “Foo”: 没有
合适的默认构造函数可用
C:\Program Files\Microsoft Visual Studio 11.0\VC\INCLUDE\xmemory0(600): 编译类 模板 成员函数
“void std::allocator<_Ty>::construct(_Ty *)”时
        with
        [
            _Ty=Foo
        ]
        C:\Program Files\Microsoft Visual Studio 11.0\VC\INCLUDE\xmemory0(751): 参见对正在编译的函数
 模板 实例化“void std::allocator<_Ty>::construct(_Ty *)”的引用
        with
        [
            _Ty=Foo
        ]
        C:\Program Files\Microsoft Visual Studio 11.0\VC\INCLUDE\type_traits(743): 参见对正在编译的
类 模板 实例化“std::allocator<_Ty>”的引用
        with
        [
            _Ty=Foo
        ]
        C:\Program Files\Microsoft Visual Studio 11.0\VC\INCLUDE\vector(655): 参见对正在编译的类 模
板 实例化“std::is_empty<_Ty>”的引用
        with
        [
            _Ty=std::allocator<Foo>
        ]
        prog26.cpp(15): 参见对正在编译的类 模板 实例化“std::vector<_Ty>”的引用
        with
        [
            _Ty=Foo
        ]

错误代码:

 

  1. #include <stdio.h>  
  2. #include <vector>  
  3. using namespace std;  
  4.   
  5. //顺序容器举例  
  6. class Foo  
  7. {  
  8. public:  
  9.     Foo(int i):ival(i){}  
  10. private:  
  11.     int ival;  
  12. };  
  13. int main(int argc, char *argv[])  
  14. {  
  15.     vector<Foo> empty;  
  16.     vector<Foo> bad(10);  
  17.     vector<Foo> ok(10,1);  
  18.     return 0;  
  19. }  

解决办法: 实际上根据c++ primer第四版解释构造空的vector时是不调用对象的构造函数的,但是这里用于 x86 的 Microsoft (R) C/C++ 优化编译器 17.00.61030编译显式错误,可能编译器版本不同结果有所不同。

主要看下面的bad(10)这一行,也同样会报错。错误的原因在于类类型对象没有默认的构造函数,因此无法正确初始化,构造vector失败。解决办法,即是为类添加默认的构造函数。

No.12  error C2440: “return”: 无法从“const Screen”转换为“Screen &”

 转换丢失限定符

出错代码:例子来自c++ primer 4th

  1. Screen& Screen::display(std::ostream& os) const  
  2. {     
  3.     os << contents << '\n';  
  4.     return *this;  
  5. }  

解决办法:  c++语言规定,不能从const成员函数返回指向类对象的普通引用,const成员函数只能返回*this作为一个const引用。因此解决办法即是,把成员函数声明为 const Screen& display(std::ostream &os) const;


No.13 error C2662: “Screen::move”: 不能将“this”指针从“const Screen”转换为“ Screen &” 转换丢失限定符

出错代码:

  1. //成员函数定义  
  2. Screen& Screen::move(index r,index c)  
  3. {  
  4.     index row = r * width;  
  5.     cursor = row + c;  
  6.     return *this;  
  7. }  
  8. const Screen& Screen::display(std::ostream& os) const  
  9. {     
  10.     os << contents << '\n';  
  11.     return *this;  
  12. }  
  13. //main中处理  
  14. myScreen.display(cout).move(4,0).set('#').display(cout);  

解决办法: 通过返回调用函数的对象的引用,可以将一些操作链接起来简化代码书写。

这里要注意,display函数返回的是const引用,因此在调用move函数中返回非const引用时无法实现转换导致出错。

解决的办法就是通过成员函数是否为const实现函数重载,定义两套函数,分别作为const成员函数和非const成员函数。

代码片段如下:

  1. //通过是否为const成员函数实现重载  
  2. Screen& display(std::ostream &os)  
  3.         {do_display(os);return *this;}  
  4. const Screen& display(std::ostream &os) const  
  5.         {do_display(os);return *this;}  
  6. //提取公共函数  
  7. void do_display(std::ostream &os) const  
  8.         {os<<contents;}  
  9. //main中处理  
  10. int main()  
  11. {  
  12.     Screen myScreen(5,3);  
  13.     const Screen blank(5,3);  
  14.   
  15.     //调用非const版本display  
  16.     myScreen.display(cout).set('#').display(cout);  
  17.     cout << endl;  
  18.   
  19.     //调用 const版本display  
  20.     blank.display(cout);  
  21.     return 0;  
  22. }  
这样非常量myScreen调用非const版本的display 函数 ,而const的blank对象调用const版本的display函数,从而避免了混淆。


No.14 error C2758: “ConstInit::cival”: 必须在构造函数基/成员初始值设定项列表中初始化

prog28.cpp(12) : 参见“ConstInit::cival”的声明

解决办法:类的成员可以在构造函数体类或者构造函数列表中初始化,但是某些类型,例如默认构造函数的类类型成员、const后者引用类型的成员则必须在构造函数初始化列表中进行初始化。例如:

  1. //const成员初始化  
  2. class ConstInit {  
  3. public:  
  4.     ConstInit(int i,int j)  
  5.     {  
  6.        ival = i;  
  7.        cival = j;  
  8.        rival = ival;  
  9.     }  
  10. private:  
  11.     int ival;  
  12.     const int cival;  
  13.     int &rival;  
  14. };  
  15. int main(int argc, char *argv[])  
  16. {  
  17.     ConstInit ci;  
  18. }  

这里引用类型rival以及const类型cival都没有在初始化列表中初始化,因此报错。解决办法就是在初始化列表中初始化这些特殊的类成员。
如下例所示:

  1. //const成员初始化  
  2. #include <iostream>  
  3. using std::cout;  
  4. class ConstInit {  
  5. public:  
  6.     ConstInit(int i=0):ival(i),cival(i),rival(i){}  
  7. private:  
  8.     int ival;  
  9.     const int cival;  
  10.     int &rival;  
  11.     //只要初始化表达式是一个常量,可以再定义体中进行初始化  
  12.     static const int period = 30;  
  13. public:  
  14.     static const unsigned int ARRAY[3];//静态常量数组  
  15. };  
  16. const unsigned int ConstInit::ARRAY[3] = {1,3,5};  
  17. int main(int argc, char *argv[])  
  18. {  
  19.     ConstInit ci;  
  20.     cout<<ConstInit::ARRAY[1];  
  21. }  

No .15 error C2248: “Foo::Foo”: 无法访问 private 成员(在“Foo”类中声明)  prog29.cpp(12) : 参见“Foo::Foo”的声明

prog29.cpp(7) : 参见“Foo”的声明

出错代码:

  1. #include <iostream>  
  2. using std::cout;  
  3. using std::endl;  
  4. //为了禁止复制,类必须显式声明其复制构造函数为private  
  5. //要禁止类的友元和成员复制对象,可以声明但不定义复制构造函数  
  6. class Foo  
  7. {  
  8. public:  
  9.     Foo(int i=0):ival(i){}  
  10.     int getVal() const {return ival;}  
  11. private:  
  12.     Foo(const Foo& orig){ival = orig.ival;};//声明为私有  
  13. private:  
  14.     int ival;  
  15. };  
  16. int main(int argc, char *argv[])  
  17. {  
  18.     Foo foo1(1);//ok,调用构造函数  
  19.     cout<<foo1.getVal()<<endl;  
  20.   
  21.     Foo foo2;  
  22.     foo2 = foo1;//ok,使用合成的赋值操作符  
  23.     cout<<foo2.getVal()<<endl;  
  24.   
  25.     Foo foo3(foo1);//error,无法调用复制构造函数  
  26.     cout<<foo3.getVal()<<endl;  
  27.     return 0;  
  28. }  

解决办法: 这里旨在说明三种初始化方式,foo1使用构造函数初始化,foo2使用默认值调用构造函数,而foo3代用私有的复制构造函数因而产生错误。注意,为了禁止复制,类必须显式声明其复制构造函数为private;要禁止类的友元和成员复制对象,可以声明但不定义复制构造函数。遇到这种错误,说明赋值构造函数函数的使用不当。

No.16 与复制构造函数相关的错误.例如:0x77D9FCAA (ntdll.dll) (prog31.exe 中)处有未经处理的异常: 0xC0000374:堆已损坏。 (参数: 0x77DC6668)。

这种错误可能就是与内存有关的释放问题。这里的错误示例代码主要是为了说明复制构造函数,尤其是含有指针类型或者有成员表示在构造函数中分配的其他资源的情况下应该应当被正确处理。

错误示例代码:

  1. #include <iostream>  
  2. #include <cstring>  
  3. using std::cout;  
  4. using std::endl;  
  5. //复制构造函数举例1  
  6. //此例包含指针成员,没有复制构造函数出错  
  7.   
  8. struct Node  
  9. {  
  10.     Node(char *n="",int a = 0)  
  11.     {    
  12.        name = strdup(n);  
  13.        strcpy(name,n);  
  14.        age = a ;  
  15.     }  
  16.     ~Node()  
  17.     {     
  18.         delete[] name;  
  19.     }  
  20.     char *name;  
  21.     int age;  
  22. };  
  23. int main()  
  24. {  
  25.     Node node1("Roger",20),node2(node1);  
  26.     //print Roger 20 Roger 20  
  27.     cout<<node1.name<<" "<<node1.age<<" "  
  28.         <<node2.name<<" "<<node2.age<<endl;  
  29.   
  30.     strcpy(node2.name,"Wendy");  
  31.     node2.age = 30;  
  32.     //print Wendy 20 Wendy 30  
  33.     cout<<node1.name<<" "<<node1.age<<" "  
  34.         <<node2.name<<" "<<node2.age<<endl;  
  35. }  


注意,这里的strdup函数是C语言中函数,它会根据串长用malloc分配内存的,返回分配的内存首地址。

这段程序执行时输出:

Roger 20 Roger 20
Wendy 20 Wendy 30
并产生错误:

0x77D9FCAA (ntdll.dll) (prog31.exe 中)处有未经处理的异常: 0xC0000374: 堆已损坏。 (参数: 0x77DC6668)。


解决办法:包含指针类型或者构造函数中包含资源分配的类,需要定义自己的复制构造函数而不是依赖编译器合成的复制构造函数。

这里依赖编译器合成的复制构造函数,从node1构造node2时,node2.name指针进行简单的重定向,定向到node1.name所指向的字符串,因此二者共享同一份字符串地址,因此再执行strcpy(node2.name,"Wendy");出现了数据不一致行的错误,两者的name全部都是Wendy,而年龄更新却是正确的。同样,由于共享同一份字符串地址,在析构函数中释放同一份内存两次,导致堆已损坏的错误。当然,如果在析构函数中删除name数组空间后,将name指针置为空,不会产生堆损坏错误。但是在析构函数中将指针置为空,将隐藏程序bug,与复制构造函数相关的错误依然存在。

因此解决的办法,就是正确定义Node类如下:

  1. #include <iostream>  
  2. #include <cstring>  
  3. using std::cout;  
  4. using std::endl;  
  5. //复制构造函数举例2  
  6.   
  7. struct Node  
  8. {  
  9.     Node(char *n="",int a = 0)  
  10.     {    
  11.        name = strdup(n);  
  12.        strcpy(name,n);  
  13.        age = a ;  
  14.     }  
  15.     //复制构造函数  
  16.     Node(const Node& node)  
  17.     {    
  18.        name = strdup(node.name);  
  19.        age = node.age;  
  20.     }  
  21.     //赋值操作符  
  22.     Node& operator=(const Node& n)  
  23.     {     
  24.         if(this != &n)  
  25.         {  
  26.             if(name != NULL)  
  27.                 delete [] name;//释放先前空间  
  28.             name = strdup(n.name);//重新分配内存  
  29.             age = n.age;  
  30.         }  
  31.         return *this;  
  32.     }  
  33.     //析构函数  
  34.     ~Node()  
  35.     {  
  36.         delete[] name;  
  37.     }  
  38.     char *name;  
  39.     int age;  
  40. };  
  41. int main()  
  42. {  
  43.     Node node1("Roger",20),node2(node1),node3("Tom",22);  
  44.     //print Roger 20 Roger 20  
  45.     cout<<node1.name<<" "<<node1.age<<" "  
  46.         <<node2.name<<" "<<node2.age<<endl;  
  47.       
  48.     strcpy(node2.name,"Wendy");  
  49.     node2.age = 30;  
  50.     //print Roger 20 Wendy 30  
  51.     cout<<node1.name<<" "<<node1.age<<" "  
  52.         <<node2.name<<" "<<node2.age<<endl;  
  53.   
  54.     //赋值操作符  
  55.     node2 = node3;  
  56.     //print Tom 22 Tom 22  
  57.     cout<<node2.name<<" "<<node2.age<<" "  
  58.         <<node3.name<<" "<<node3.age<<endl;  
  59.       
  60.     return 0;  
  61. }  

这里因为可以由三法则(Rule of Three)即一个类如果需要析构函数,则该类几乎也必然需要定义自己的复制构造函数和赋值操作符解释。重新运行程序,即可得到正确结果并避免堆损坏错误。

No.17   error C2664: “std::list<_Ty>::list(const std::allocator<_Ty> &)”: 不能将参数 1 从“std::vector<_Ty>”转换为“const std::allocator<_Ty> &”

        with
        [
            _Ty=int
        ]
        原因如下: 无法从“std::vector<_Ty>”转换为“const std::allocator<_Ty>”
        with
        [
            _Ty=int
        ]
        没有可用于执行该转换的用户定义的转换运算符,或者无法调用该运算符
prog33.cpp(13) : error C2664: “std::vector<_Ty>::vector(const std::allocator<_Ty> &)”: 不能将参数
1 从“std::vector<_Ty>”转换为“const std::allocator<_Ty> &”
        with
        [
            _Ty=double
        ]
        and
        [
            _Ty=int
        ]
        and
        [
            _Ty=double
        ]
        原因如下: 无法从“std::vector<_Ty>”转换为“const std::allocator<_Ty>”
        with
        [
            _Ty=int
        ]
        and
        [
            _Ty=double
        ]
        没有可用于执行该转换的用户定义的转换运算符,或者无法调用该运算符

错误代码:

  1. #include <iostream>  
  2. #include <vector>  
  3. #include <list>  
  4. using std::vector;  
  5. using std::list;  
  6. using std::cout;  
  7. //容器初始化举例  
  8. int main()  
  9. {  
  10.     vector<int>   ivec;//使用默认构造函数  
  11.     vector<int>   ivec2(ivec);//初始化为同型容器的副本  
  12.     list<int> ilist(ivec);//错误,容器类型不同  
  13.     vector<double>    dvec(ivec);//错误,容器元素类型不同  
  14.       
  15.     return 0;  
  16. }  
解决办法:  c++标准库中不允许容器初始化为不同类型或者容器元素类型不同的容器的副本。如果需要从其他容器的元素初始化容器,可以使用一对迭代范围的构造函数初始化。例如:

  1. vector<int>    ivec;  
  2.   
  3. list<int>   ilist(ivec.begin(),ivec.end());  
  4.  vector<double>    dvec(ivec.begin(),ivec.end());  


No.18 与迭代器失效相关的错误,例如:0x008D1127 处有未经处理的异常(在 prog34.exe 中): 0xC0000005: 读取位置 0x010AC000 时发生访问冲突。

错误代码:

  1. #include <iostream>  
  2. #include <vector>  
  3.   
  4. using std::vector;  
  5. using std::cout;  
  6. using std::endl;  
  7. //迭代器失效举例-避免存储end操作返回的迭代器  
  8. int main()  
  9. {  
  10.     vector<int>   ivec;  
  11.     ivec.push_back(3);  
  12.     ivec.push_back(5);  
  13.     ivec.push_back(7);  
  14.     vector<int>::iterator end = ivec.end();  
  15.       
  16.     for(vector<int>::iterator first = ivec.begin();first != end;++first)  
  17.         cout<<*first<<endl;  
  18.       
  19.     ivec.insert(ivec.begin(),1);  
  20.     //cause fatal error  
  21.     for(vector<int>::iterator first = ivec.begin();first != end;++first)  
  22.         cout<<*first<<endl;  
  23.     return 0;  
  24. }  

解决办法:  这里保存了end操作返回的迭代器,然后又在容器中执行插入操作,导致迭代器失效,因而第二次的输出操作无法正常结束导致死循环,产生访问冲突。要警惕迭代器失效的操作,c++ primer建议假设迭代器失效是最安全的做法。这里可以在for语句中重新获取迭代器,以避免此类错误。

No.19 ...VC\INCLUDE\iterator(93) : error C2039: “push_front”:

不是“std::vector<_Ty>”的成员

        with
        [
            _Ty=int

        ]

错误代码:

  1. int ia[] = {1,5,3,3,4};  
  2. const int array_size = sizeof(ia)/sizeof(*ia);  
  3. list<int> ilist(ia,ia+array_size);  
  4. vector<int> temp;  
  5. copy(ilist.begin(),ilist.end(),  
  6. front_inserter(temp));//使用push_front插入,导致错误  

解决办法: 迭代器与底层容器之间的操作实际上存在限制关系,也就是说并不是所有的容器都支持诸如push_front之类的操作。这里front_inserter将使用push_front方法来向vector插入元素,但是vector并不支持push_front操作。因此,解决的方法就是使用back_inserter 或者inserter函数返回的插入迭代器来进行操作。

NO.20 类模板使用时 TestDrive.obj : error LNK2019: 无法解析的外部符号 "public: __thiscall LinkedList<int>::~LinkedList<int>(void)" (??1?$LinkedList@H@@QAE@XZ),该符号在函数 _main 中被引用.

错误代码:

LikedList.h

  1. #ifndef _PAIR_H_  
  2. #define _PAIR_H_  
  3. #include <string>  
  4. template <class T>   
  5. class Node  
  6. {    
  7. public:  
  8.     Node(T dat,Node *n=NULL):data(dat),next(n){}  
  9. public:  
  10.     T data;  
  11.     Node *next;  
  12. };  
  13. template <class T>   
  14. class LinkedList  
  15. {  
  16. public:  
  17.      LinkedList():head(NULL){}  
  18.      ~LinkedList();//free space here  
  19.      void add(T e);//add element  
  20.      std::string toString();//print content  
  21. public:  
  22.     Node<T> *head;  
  23. };  
  24. #endif  
LinkedList.cpp

  1. #include "LinkedList.h"  
  2. //free space  
  3. template <class T> LinkedList<T>::~LinkedList()  
  4. {  
  5.    Node<T> * ptr = head;  
  6.    while(ptr != NULL)  
  7.    {  
  8.       Node<T> * tmp = ptr->next;  
  9.       delete ptr;  
  10.       ptr = tmp;  
  11.    }  
  12. }  
  13. template <class T> void LinkedList<T>::add(T e)  
  14. {  
  15.     Node<T> *node = new Node<T>(e);  
  16.     node->next = head;  
  17.     head = node;//update head  
  18. }  
  19. template <class T> std::string LinkedList<T>::toString()  
  20. {  
  21.    std::string asString("List:[");   
  22.    for(Node<T>* ptr = head;ptr != NULL;ptr = ptr->next)  
  23.         asString += std::to_string(ptr->data);  
  24.    asString += "]";  
  25.    return asString;  
  26. }  
TestDrive.cpp

  1. #include <iostream>  
  2. #include "LinkedList.h"  
  3.   
  4. int main()  
  5. {  
  6.     LinkedList<int> list;  
  7.     list.add(1);  
  8.     list.add(2);  
  9.     list.add(3);  
  10.     std::cout<<list.toString()<<std::endl;  
  11.     return 0;  
  12. }  

解决办法: 模板类文件编译要采取一些手段。

主要有两种方式,方式一在头文件中包含类的实现,合并成一个文件来编译.

方式二,通过使用export关键字,让编译器知道要记住给定的模板定义。当然要看编译器支持否,我的vs2013编译提示, warning C4237: 目前还不支持“export”关键字,但已保留该关键字供将来使用。因此这里使用方式一,例如代码:

  1. #ifndef _PAIR_H_  
  2. #define _PAIR_H_  
  3. #include <string>  
  4. template <class T>   
  5. class Node  
  6. {    
  7. public:  
  8.     Node(T dat,Node *n=NULL):data(dat),next(n){}  
  9. public:  
  10.     T data;  
  11.     Node *next;  
  12. };  
  13. template <class T>   
  14. class LinkedList  
  15. {  
  16. public:  
  17.      LinkedList():head(NULL){}  
  18.      ~LinkedList();//free space here  
  19.      void add(T e);//add element  
  20.      std::string toString();//print content  
  21. public:  
  22.     Node<T> *head;  
  23. };  
  24.   
  25. template <class T> LinkedList<T>::~LinkedList()  
  26. {  
  27.    Node<T> * ptr = head;  
  28.    while(ptr != NULL)  
  29.    {  
  30.       Node<T> * tmp = ptr->next;  
  31.       delete ptr;  
  32.       ptr = tmp;  
  33.    }  
  34. }  
  35. template <class T> void LinkedList<T>::add(T e)  
  36. {  
  37.     Node<T> *node = new Node<T>(e);  
  38.     node->next = head;  
  39.     head = node;//update head  
  40. }  
  41. template <class T> std::string LinkedList<T>::toString()  
  42. {  
  43.    std::string asString("List:[");   
  44.    for(Node<T>* ptr = head;ptr != NULL;ptr = ptr->next)  
  45.         asString += std::to_string(ptr->data);  
  46.    asString += "]";  
  47.    return asString;  
  48. }  
  49. #endif  
测试结果:

List:[321].

No 21: 类成员变量和函数重名问题   error C2365: “ArrayStack<T>::top”: 重定义;以前的定义是“成员函数”

这个错误发生纯属意外,但是让人纠结了半天。在c++中类的成员变量和函数是不可以重名的,这与java之中不同。例如使用数组实现一个栈时,ArrayStack类的top指针成员和基类的函数top重名,导致的错误,一开始让人莫名其妙。

错误代码:

Stack基类中声明了函数top:

  1. template<typename T>  
  2. class Stack  
  3. {  
  4. public:  
  5.       virtual ~Stack(){};  
  6.       virtual void push(T data)=0;  
  7.       virtual T pop()=0;  
  8.       virtual T top()=0;  
  9.       virtual bool isEmpty()=0;  
  10.       virtual void clear() = 0;  
  11.       virtual int getSize()=0;  
  12. };  

利用数组实现时:

  1. template<typename T = int>  
  2.   
  3. class ArrayStack : public Stack<T>  
  4. {  
  5. public:  
  6.       T top()  
  7.       {  
  8.          if(top == base)  
  9.         {  
  10.            throw std::logic_error("top at empty stack");  
  11.         }  
  12.         return *(top-1);  
  13.       }  
  14.       //other member function  
  15. private:  
  16.       T *base,*top;  
  17.       int capacity;  
  18. };  
因为 类使用了指针top,同时实现了函数top,重名错误 ,因此导致了编译器给出如下错误信息:

[plain]  view plain copy print ?
  1. d:\ds\stack\ArrayStack.h(79) : error C2365: “ArrayStack<T>::top”: 重定义;以前的定义是“成员函数”  
  2.   
  3.         d:\ds\stack\ArrayStack.h(58) : 参见“ArrayStack<T>::top”的声明  
  4.         d:\ds\stack\ArrayStack.h(81): 参见对正在编译的类 模板 实例化“ArrayStack<T>”的引用  
  5. d:\ds\stack\ArrayStack.h(79) : error C2365: “ArrayStack<T>::top”: 重定义;以前的定义是“成员函数”  
  6.   
  7.         with  
  8.         [  
  9.             T=int  
  10.         ]  
  11.         d:\ds\stack\ArrayStack.h(58) : 参见“ArrayStack<T>::top”的声明  
  12.         with  
  13.         [  
  14.             T=int  
  15.         ]  
  16.         StackTest.cpp(6): 参见对正在编译的类 模板 实例化“ArrayStack<T>”的引用  
  17.         with  
  18.         [  
  19.             T=int  
  20.         ]  
解决办法,遵照合理的命名规则。

No.22 使用标准库sort等方法却未定义关系操作符  algorithm(3618) : error C2784: “bool std::operator <(const std::basic_string<_Elem,_Traits,_Alloc> &,const _Elem *)”: 未能从“Person”为“const std::basic_string<_Elem,_Traits,_Alloc> &”推导模板参数

...(省略)
algorithm(3619) : error C2676: 二进制“<”:“Person”不定义该运算符或到预定义运算符可接收的类型的转换


错误代码示例:

  1. #include <vector>  
  2. #include <algorithm>  
  3. #include <iostream>  
  4. #include <string>  
  5.   
  6. class Person  
  7. {  
  8. public:  
  9.     // default constructor  
  10.     Person() : age(0) {}  
  11.     Person(int age, std::string name) {  
  12.         this->age = age; this->name = name;  
  13.     }  
  14.     int age;  
  15.     std::string name;  
  16. };  
  17.   
  18. int main()  
  19. {  
  20.     std::vector<Person> vecPerson;  
  21.     vecPerson.push_back(Person(24,"Calvin"));  
  22.     vecPerson.push_back(Person(30,"Benny"));  
  23.     vecPerson.push_back(Person(28,"Alison"));  
  24.   
  25.     std::sort(vecPerson.begin(),vecPerson.end());  
  26.     //using c++11  
  27.     for(const Person& p : vecPerson)  
  28.         std::cout<<p.age<<", "<<p.name<<std::endl;  
  29.   
  30.     return 0;  
  31. }  
解决办法:  定义STL算法需要的关系操作符。在上例中,sort算法默认使用std::less,而std::less使用类的<操作符,因此可以定义一个全局的 重载<操作符 的函数来满足sort算法需求,如下:

  1. inline bool operator<(const Person& a, const Person& b)  
  2. {  
  3.     return a.age < b.age;  
  4. }  

程序输出:

24, Calvin
28, Alison
30, Benny

No.23  error C2661: “std::less<_Ty>::less”: 没有重载函数接受 2 个参数

Std::less<T>是一个函数对象,错误在于没有正确的使用函数对象。

错误代码示例:

  1. template<typename T,typename Compare=std::less<T> >  
  2. class PriorityQueue : public Queue<T>  
  3. {  
  4.    template<typename T,typename Compare>  
  5. T PriorityQueue<T,Compare>::dequeue()  
  6. {  
  7.     if(index == 0)  
  8.     {  
  9.        std::cerr<<"logic error : dequeue at empty queue. "<<std::endl;  
  10.        throw std::logic_error("dequeue at empty queue");  
  11.     }  
  12.     //pick up one with highest priority   
  13.     int highIndex = 0;  
  14.     for(int i = 1;i < index ;i++)    // O(n)  
  15.     {  
  16.         if( Compare( queue[i],queue[highIndex] ) )  
  17.             highIndex = i;  
  18.     }  
  19.     T result = queue[highIndex];  
  20.     index--;  
  21.     queue[highIndex] = queue[index];    //put the last element to the removed position  
  22.       
  23.     return result;  
  24. }  
  25. }  

错误的代码出现在: if ( Compare( queue[i],queue[highIndex] ) )。

Compare是一个函数对象,函数对象使用方式两种:

第一种,显式构造一个函数对象,然后使用它,例如:

  1. std::less<Key> a;  //定义一个函数对象  
  2.   
  3. if(a(x,y)) ...     

第二种,在使用时构造,例如:

  1. if(std::less<Key>()(x,y)) ...  

对于上述代码中, 解决办法 :代码更正为:if( Compare()( queue[i],queue[highIndex] ) )。

原文出处: http://blog.youkuaiyun.com/wangdingqiaoit/article/details/8630900
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值