使用cppcheck給工程代碼作靜態檢查,主要發現瞭如下幾個問題:c++
警告以下:程序員
C-style pointer casting detected. C++ offers four different kinds of casts as replacements: static_cast, const_cast, dynamic_cast and reinterpret_cast. A C-style cast could evaluate to any of those automatically, thus it is considered safer if the programmer explicitly states which kind of cast is expected. See also: https://www.securecoding.cert.org/confluence/display/cplusplus/EXP05-CPP.+Do+not+use+C-style+casts.
編程
應該使用C++提供的static_cast, const_cast, dynamic_cast 和 reinterpret_cast 作類型轉換,明確轉換的類型。ide
警告以下:函數
Prefix ++/-- operators should be preferred for non-primitive types. Pre-increment/decrement can be more efficient than post-increment/decrement. Post-increment/decrement usually involves keeping a copy of the previous value around and adds a little extra code.
post
迭代器前置++和後置++ 的運行效率是不一樣的,前置++效率更高,由於後置運算符須要作一個臨時的類對象拷貝。測試
警告以下:this
The conversion from const char* as returned by c_str() to std::string creates an unnecessary string copy. Solve that by directly passing the string.
編碼
好比一個函數的參數類型是strng,調用時實參直接使用了C風格的字符串,因而就會有以上提示,主要仍是由於這裏會形成一個沒必要要的字符串拷貝,下降運行效率。lua
不少時候,咱們會寫下面的find代碼,值不等於-1則說明找到了該字符串,
if(std::string::npos != dataStr.find("what")) //do something
該代碼段會致使報警:
Either inefficient or wrong usage of string::find(). string::compare() will be faster if string::find's result is compared with 0, because it will not scan the whole string. If your intention is to check that there are no findings in the string, you should compare with std::string::npos.
代碼自己不會出錯,可是效率上是不被承認的,如cppcheck所說,若是你但願檢查某個字符串是否是某個指望的字符串,那你應該使用compare函數,由於這樣更快。
警告以下:
Parameter 'strShowTime' is passed by value. It could be passed as a const reference which is usually faster and recommended in C++.
C++給了引用傳參,而你不使用,那就是你的問題了。
警告有:
Member variable 'CActiveComboItemXml::m_phorActivecombo' is not initialized in the constructor.
或者如:
When an object of a class is created, the constructors of all member variables are called consecutively in the order the variables are declared, even if you don't explicitly write them to the initialization list. You could avoid assigning 'm_strHrefOnPanReady' a value by passing the value to the constructor in the initialization list.
這個問題很廣泛,由於不少程序員不習慣在構造函數的初始化列表中初始化成員變量,有的是直接忽略掉,有的則是在構造函數的函數體中去使用賦值運算符賦值,但是這個時候已經不是初始化了,而是賦值階段了。這是個很危險的習慣!
警告爲:
Using 'memset' on struct that contains a 'std::wstring'. [memsetClass]
在C語言中,使用memset清空內存是經常使用操做,在C++中,和malloc同樣,使用memset直接操做內存是有很大風險的,由於它們都只是在內存層面作了改動,可是對類對象自己卻沒有任何行動,也就是說,他們不會調用類對象的構造或者析構函數,若是咱們的結構體中含有string類型的成員,直接使用memset極可能致使內存泄漏!
這裏涉及到一個POD參考的概念。若是一個類不是POD的,那麼就不該該使用如mem*,malloc等內存操做函數,不然,咱們將得不到咱們想要的東西,甚至引起錯誤。
舉一個很簡單的例子:
struct struTest { string str1; }; void TestStructString() { struTest tt; size_t sizestru = sizeof(tt); tt.str1 = "this OK"; struTest* tt2 = new struTest; memcpy(tt2,&tt,sizestru); cout << "tt2 str1 is:"<<tt2->str1 <<"\n"; delete tt2; //程序奔潰!!! }
測試程序以memcpy函數爲例,運行本程序,雖然tt2能夠正常的將str1拷貝進來,可是最後程序奔潰了!!
想一想緣由是爲什麼? 程序崩潰在tt的析構函數中,由於沒法探究memcpy到底作了哪些具體操做,因此咱們能夠猜想它是將tt的內存區域完整的拷貝到了tt2內,可是,tt2中的strin類型的成員str1並無完成本身的構造,而是經過內存拷貝的方式完整的使用了tt的數據,那麼執行完delete ,tt2的str1也會析構自身,這時其析構的實際上是tt的str1。等到tt再去析構本身時,奔潰就發生了!以上只是本身的猜想。可能不是事實,可是,當我把delete tt2
註釋後,崩潰就消失了,這也能證實本身上面的論述。
問題怎麼處理?
在C++中,除非是明確的POD類型,不然放棄使用mem*系包括malloc等傳統C內存操做函數。
首先,咱們須要弄明白,咱們爲何須要使用memet,由於咱們須要將這個結構體的數據清零,因此咱們真正須要的是一個結構體(類)的構造函數!在類中寫一個結構體,將類裏的全部成員變量進行列表初始化就能夠解決這個問題了。
話說回來,就好像,咱們在寫C代碼時, 若是結構體某個成員類型須要是結構體類型,咱們使用了該結構體指針同樣,咱們一樣可使用string類型的指針來表示該成員類型。畢竟在VS2010環境下,一個string類型的內存佔用就是32byte,而一個string*只有4byte。若是擔憂hold不住指針類型,可使用智能指針來折中,如shared_ptr,內存的佔用將減少到8。事實上,使用智能使用已是一個最優方案了。
這幾個問題大量出如今cppcheck的問題列表中,是咱們常常犯的編程問題,應從代碼風格上進行規避。
固然了,可能的錯誤(警告)是由不當的編碼風格和不紮實的C++編碼基礎致使的,經過靜態檢查咱們本身的代碼,能夠最大層度的寫出易讀且不容易出錯的代碼。
推薦你們使用cppcheck!