你须要的代码静态检查

代码静态检查

使用cppcheck给工程代码作静态检查,主要发现了如下几个问题:c++

1. 使用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

2. 迭代器使用后置叠加(叠减)运算符

警告以下:函数

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

迭代器前置++和后置++ 的运行效率是不一样的,前置++效率更高,由于后置运算符须要作一个临时的类对象拷贝。测试

3. 直接在函数参数中使用C风格字符串。

警告以下: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

4. 使用无用的find

不少时候,咱们会写下面的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函数,由于这样更快。

5. 函数参数使用传值而不是传引用

警告以下:

Parameter 'strShowTime' is passed by value. It could be passed as a const reference which is usually faster and recommended in C++.

C++给了引用传参,而你不使用,那就是你的问题了。

6. 构造函数没有使用初始化成员变量列表,而是习惯于写入构造函数体

警告有:

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.

这个问题很广泛,由于不少程序员不习惯在构造函数的初始化列表中初始化成员变量,有的是直接忽略掉,有的则是在构造函数的函数体中去使用赋值运算符赋值,但是这个时候已经不是初始化了,而是赋值阶段了。这是个很危险的习惯!

7.使用memset清空含有string(wstring)类型成员的结构体

警告为:
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!

相关文章
相关标签/搜索