函数调用的效率(转)

一、函数、宏、内联函数
1、函数
    调用函数的开销大致可分两个部分:传递参数的开销和保存当前程序上下文信息所花费的开销。对于
传递参数的开销而言,传递的参数越多开销就越大;对于保存当前程序上下文所花费的开销而言,函数越
复杂需要花费的开销就越大。
2、宏
    宏在某种程度上可以代替函数,避免函数调用带来的开销。定义完宏之后,在编译程序时,用替代字
符串代替程序中的宏。
    对于宏而言,虽然避免了函数调用带来的开销,但是增加了内存的开销。因为在每个应用宏的地方宏
都会展开。
    另外,宏易读性比较差,容易出现问题。例如:

#define MAX(a,b) ((a) < (b) ? (b):(a))
void main()
{
        int a = 10;
        int b = 11;
        int c = 0;
        c = MAX(a++,b++);
        cout << c << endl;
        cin >> c;
}


    我们会发现c的结果为12,因为宏展开之后变为:((a++) < (b++) ? (b++) : (a++))并不是我们预想
中的结果。故一般来讲最好不使用宏。
3、内联函数
    内联函数是避免函数调用开销的另一种方法,与宏类似,在程序编译是用内联函数替换函数调用。但
只能运用与C++中,C中无法使用。与宏相比拥有参数类型检查的优点。
    在C++类中,对于设置和读取私有变量的函数设置为内敛函数,有助于提高函数的效率。
内敛函数的实现有两种方式,第一种是在函数定义时使用关键字inline,第二种方式时在函数定义时与函
数体一起定义。
4、递归与迭代
    递归可以使程序显得短小精悍,然而由于函数的多层调用,会严重影响程序的运行效率和内存使用效
率。幸运的是在某种情况下,我们可以使用迭代来代替递归,避免函数调用开销。
例子:
递归版计算n的阶乘

long Factorial(int n)
{
        if(n == 0)
        {
                return 1;
        }
        else
        {
                return Factorial(n-1);
        }
}


迭代版计算n的阶乘

long Factorial(int n)
{
        int fac = 1;
        while(n != 0)
        {
                fac *= n;
                n--;
        }
        return fac;
}


二、函数的参数传递
    函数参数的多少直接影响到函数调用的开销,故编写函数时需要选择恰当的参数传递方式。我们可以
用三种方式来传递函数:按值传递、按引用传递和通过全局变量传递。
    按值传递参数时,需要把所需传递的参数全部复制到堆栈中,当函数访问该参数时相当于访问局部变
量,为直接寻址;按引用传递参数时,复制到堆栈中的时指针所包含的地址,当函数访问该参数时相当于
间接寻址,增加了访问参数的时间。通过全局变量传递数据,避免了函数调用的开销,拥有较高的效率,
但会影响程序的可维护性,故非在非常明确的情况下,慎用全局变量。
    当需要通过函数修改参数值时,通过引用传递参数或通过全局变量是不二的选择。
    当无需通过函数修改参数值时,对于较小的参数(占用字节少)采用按值传递较之按引用传递较好,
对于占用较多字节的参数(结构体、类等)时,采用按引用传递的方式有助于减少函数参数传递的开销。
三、类对象的高效初始化
1、类对象初始化
    构造一个对象类并设置其私有数据成员,通常有两种方法,第一种是首先通过无参构造函数创建类对
象,再通过私有数据设置函数设置成员数据的值;第二种是通过带有参数的构造函数,同时创建类对象并
设置私有数据成员的值。较第一种方法而言,第二种方式显然拥有更高的效率,因为,调用私有数据成员
设置函数同样需要花费函数调用的开销。故当我们能够一次性完成创建与初始化时,最好采用第二种方案

低效类对象初始化:
People peo;
peo.SetName("John");
peo.SetAge(23);
peo.SetSex("man");
高效类对象初始化:
People peo("John", 23, "man");
2、基类初始化
    当创建类对象时,若该类存在基类,则先调用基类的构造函数,在不采用基类初始化方式的情况下,
系统调用基类的默认构造函数(无参构造函数)。此时若需设置基类的私有数据成员,必须调用基类的私
有成员设置函数,从而增加函数调用的开销。故在能够同时提供基类私有数据成员的情况下,尽量采用基
类初始化的方式初始化基类。
低效基类初始化:

Student::Student(string myName, int myAge, int mySex, int myGrade)
{
        SetName(myName);
        SetAge(myAge);
        SetSex(mySex);
        grade = myGrade;
}


高效基类初始化:

Student::Student(string myName, int myAge, int mySex, int myGrade):
People(myName, myAge, mySex, myGrade)
{
        this->grade = myGrade;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值