提升C++程序效率中的10个技巧

来源:互联网 发布:php curl post提交 编辑:程序博客网 时间:2024/06/05 18:55

C++作为一个强大又注重效率的语言,虽然它效率很高,但是我们在实际应用中利用一些技巧,使其效率更高也是很有必要的:

(1)函数的参数传引用比传值效率更高。尤其是参数为类对象的时候;

bool Compare(string s1)bool Compare(string *s1) //传指针;bool Compare(string &s1) //传引用;bool Compare(const string &s1) //常量引用,否则不能引用常量;
        第一个函数(值传递),则在参数传递和函数返回时,需要调用string的构造函数和析构函数两次,而其他的三个函数---指针传递和引用传递--则不需要调用这两个个函数。因为指针和引用都不会创建新的对象。如果一个构造一个对象和析构一个对象的开销是庞大的,这就是会效率造成一定的影响。引用与使用普通值传递一样方便直观,同时具有指针传递的高效和能力。因为引用是一个变量的别名,对其操作等同于对实际对象操作,所以当你确定在你的函数是不会或不需要变量参数的值时,就大胆地在声明的前面加上一个const吧,就如最后的一个函数声明一样。同时加上一个const还有一个好处,就是可以对常量进行引用,若不加上const修饰符,引用是不能引用常量的。

(2)尽可能多地使用const

const int Max = 100; voidf(const int i) { .........}//对传入的参数进行类型检查,不匹配进行提示class A{           ...... void f(int i)       {......} //一个函数 void f(int i) const {......} //上一个函数的重载           ......};#definePI 3.14159         //常量宏const doulbe Pi=3.14159; //此时并未将Pi放入ROM中

         编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高

(3)对于类的对象有赋值和初始化时优先选择初始化,因为这样可以避免生成临时对象,赋值会产生临时对象;

father f1;father f2(f1); //直接初始化;father f3=f1; //赋值初始化;
        当用于类类型对象时,初始化的复制形式和直接形式有所不同:直接初始化直接调用与实参匹配的构造函数,复制初始化总是调用复制构造函数。复制初始化首先使用指定构造函数创建一个临时对象,然后用复制构造函数将那个临时对象复制到正在创建的对象。创建临时对象就会调用构造函数和析构函数,多了两次函数调用,增减了开销。

(4)如果选择为if-if-if-,则应选择if-else if-else或是switch-case;后两者比较的次数少,效率高;
例如:

if(1==a) {dosomething;}if(2==a) {dosomething;}if(3==a) {dosomething;}以上三个if都得执行,但是下面的:switch(a){case 1:do something; break;case 2:do something; break;case 3:do something; break;}只会执行一个case语句,提高了效率。

(5)对于重载自定义的++i和i++,++i比i++的效率高;
        原因: ++i在运算过程中不产生临时对象,返回的就是i,是个左值,类似++i=1这样的表达式是合法的,而i++在运算的过程中会产生临时对象,返回的是零时对象的值,是个右值,像i++=1这样的表达式是非法的;
对于内置类型,单独的i++和++i语句,现在的编译器基本上都会优化成++i,所以就没什么区别了。
      例如:下面的链表内部迭代器

List::Iterator& List::Iterator::operator++()//前加{pNote = pNote->pNext;return *this;}List::Iterator List::Iterator::operator++(int)//后加{Iterator tmp(*this);pNote = pNote->pNext;return tmp;}从后加的方式可以知道,对象利用自己创建一个临时对象,然后改变自己的状态,并返回这个临时对象,而前加的方式直接改变自己的状态,并返回自己的引用!由于迭代器一般都是遍历容器的,大数应用于循环,所以如果该链表有100个元素,如下代码所示:for(_SingleList::Iterator it = list.begin(); it != list.end(); ++it){//do something}for(_SingleList::Iterator it = list.begin(); it != list.end(); it++){//do something}那么第二个代码就要调用200多个函数这样程序的效率就不可忽视了!

(6)如果程序中cout使用次数很少或只用一次,则可以使用std::cout来节省空间。
        因为这样比导入整个命名空间更经济;

(7)减少除法的使用。
        无论是整数还是浮点数运算,除法都是一件运算速度很慢的指令,在计算机中实现除法是比较复杂的。所以要减少除法运算的次数。我们可以通过移位,或者转化为乘法来做除法运算。

例如:4/2 ---- 4>>1;if(a>b/c) ----if(a*c>b)

(8)对于类的对象返回引用比返回对象的效率要高。
        因为不会调用拷贝构造函数,生成临时对象;但是特别注意临时对象和局部变量不能返回引用;
(9)避免使用多重继承
        在C++中,支持多继承,即一个子类可以有多个父类。书上都会跟我们说,多重继承的复杂性和使用的困难,并告诫我们不要轻易使用多重继承。其实多重继承并不仅仅使程序和代码变得更加复杂,还会影响程序的运行效率。这是因为在C++中每个对象都有一个this指针指向对象本身,而C++中类对成员变量的使用是通过this的地址加偏移量来计算的,而在多重继承的情况下,这个计算会变量更加复杂,从而降低程序的运行效率。而为了解决二义性,而使用虚基类的多重继承对效率的影响更为严重,因为其继承关系更加复杂和成员变量所属的父类关系更加复杂。
(10)将小粒度函数声明为内联函数(inline)
         由于调用函数是需要保护现场,为局部变量分配内存,函数结束后还要恢复现场等开销,而内联函数则是把它的代码直接写到调用函数处,所以不需要这些开销,但会使程序的源代码长度变大。所以若是小粒度的函数,如下面的Max函数,由于不需要调用普通函数的开销,所以可以提高程序的效率。

int Max(int a, int b){return a>b?a:b;}


 


原创粉丝点击