c++ primer學習過程中調試常見錯誤歸納
這是學習c++ primer過程中練習程式時,調試時出現的錯誤即解決方案列表,不斷更新。
No.1: 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
//prog2.cpp#include <iostream>#include <list>#include <deque>using namespace std;void main(){ //Define a list that holds elements that are deques that hold ints deque<int> ideque(10,1); list<int> ilist(ideque.begin(),ideque.end()); for(list<int>::const_iterator itbegin=ilist.begin(),itend=ilist.end();itbegin!=itend;++itbegin) cout<<*itbegin<<endl;}
解決方案:vc 6.0對模板庫支援不夠好,使用vs2010編譯通過。
No.2 TextQuery.cpp(63) :
warning C4172: returning address of local variable or temporary
//返回單詞出現的行號setconst set<int> & TextQuery::RunQuery(string word) const{ map< string,set<int> >::const_iterator it = m_mapWordLine.find(word); if(it != m_mapWordLine.end())return it->second; elsereturn set<int>();//emptyset}
解決方案:願意是返回set對象的const引用以減輕複製set對象的負擔,但是這裡返回空的set對象的局部引用是錯誤的,c++ primer 原文採用的方法是返回set對象,不使用引用,這也是一種解決方案。另外使用std::vector<std::string>::size_type 比int型的set好。
No.3 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
//輸出一行中所有字元void printchar(string &line){ istringstream iss(line);string word;while(iss>>word) for(vector<string>::const_iterator itbegin=word.begin(),itend=word.end();itbegin != itend; ++itbegin)cout<<*itbegin<<endl;}
解決方案:標準庫string對象可以使用迭代器操作 ,但是其迭代器要正確使用,應該使用string::const_iterator 後者使用下標操作來擷取string對象中的字元。
No.4 嚴重錯誤 "vector iterator + offset out of range" "standard C++ libraries out of range "
代碼如下:
#include <iostream>#include <iterator>//使用back_inserter #include <algorithm>#include <vector>using namespace std;void main(){ vector<int> ivec; try { fill_n(ivec.begin(),10,1);//error should use fill_n (back_inserter(ivec), 10, 1); for(vector<int>::iterator itbegin=ivec.begin(),itend=ivec.end();itbegin!=itend;++itbegin) cout<<*itbegin<<endl; } catch (runtime_error err) { cerr << "Error: "<<err.what()<<endl; } catch(out_of_range or) { cerr << "Error: "<<or.what()<<endl; } catch(exception ex) { cerr << "Error: "<<ex.what()<<endl; } }
解決方案:fill_n()函數將在vector中從頭開始,將指定個數的元素設定為給定的值。fill_n函數假定對指定數量的元素做寫操作是安全的。初學者常犯的錯誤的是:在沒有元素的空容器上調用 fill_n 函數,因此需要使用back_inserter ,這種插入迭代器。當使用插入迭代器賦值時,則會在容器中添加一個新元素,其值等於賦值運算的右運算元的值。因此需將代碼改為:
fill_n (back_inserter(ivec), 10, 1);
No.5 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 *'
代碼如下:
#include <iostream>#include <algorithm>#include <vector>using namespace std;void main(){ vector<int> ivec1(10,1); sort(ivec1.begin(), ivec1.rend());//類型不符的錯誤 可以在編譯時間檢查出來}
解決方案:
sort函數重載有兩個版本,所以出現上面的錯誤提示,無論哪個版本,要求給定一對迭代器範圍,而在標準庫中,有輸入範圍的泛型演算法要求其兩個迭代器類型完全一樣,包括const屬性。要麼都是const,要麼都是非const,否則無法通過編譯。
上述的begin函數返回是普通迭代器,而rend函數返回的是反向迭代器,因此兩個實參類型不符,出現了上述錯誤,解決方案就是正確的傳遞實參,使用類型完全一樣的迭代器標記範圍。
No.6 ..\sales_item\sales_item.h(24) :error C2804: binary 'operator +' has too many parameters
代碼如下:
// header file Sales_item.h#include <iostream>#include <string>class Sales_item { // private members private:std::string isbn; unsigned units_sold;double revenue; //public methodpublic:.. //Overloaded Operator as member function Sales_item& operator+=(const Sales_item&);//Compound Assignment OperatorsSales_item operator+(const Sales_item& lhs, const Sales_item& rhs);};// implement file Sales_item.cppusing std::istream; using std::ostream;//Overloaded Operator as nonmember functionsinline Sales_item Sales_item::operator+(const Sales_item& lhs, const Sales_item& rhs){ Sales_item ret(lhs); // copy lhs into a local object that we'll return ret += rhs; // add in the contents of rhs return ret; // return ret by value ,not by reference}
解決方案:+操作符包括兩個運算元,應該重載為普通非成員函數。
注意重載操作符的形參數目(包括成員函數的隱式 this 指標)與操作符的運算元數目相同。對稱的操作符,如算術操作符、相等操作符、關係操作符和位操作符,最好定義為普通非成員函數。因此+應該重載為普通非成員函數。這裡重載為成員函數時多了一個this形參,故對於+操作符來說,出現參數過多的錯誤。
即書寫為:
// header fileSales_item operator+(const Sales_item& lhs, const Sales_item& rhs);//implement file//Overloaded Operator as nonmember functionsinline Sales_item operator+(const Sales_item& lhs, const Sales_item& rhs){ Sales_item ret(lhs); // copy lhs into a local object that we'll return ret += rhs; // add in the contents of rhs return ret; // return ret by value ,not by reference}
No.7 Compiling...main.cppLinking...main.obj :
error LNK2001: unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char> > &__cdecl
operator<<(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函數的實現放置在標頭檔中。具體請參考:《類的內嵌函式的實現應該放在哪裡》一文。