我们在声明一个变量的时候,会伴随着对该变量构造函数的执行,当程序跳出变量作用域的时候,又会执行变量的析构函数,对于一些比较复杂的对象,这是一笔不小的开支,为此,我们应尽量避免一些没有用到的变量的定义,看看下面这段代码:
std::string ExampleFun(const std::string& strParam)
{
std::string strRet;
if(......)
{......} //在执行期间,可能抛出异常
return strRst;
}
我们希望通过ExampleFun函数得到一个字符串strRet,如果在函数体内程序抛出异常,函数可能最终在if的执行语句内就返回了,而strRet没有被使用,此时就白白付出了对strRet的构造和析构的成本。较好的做法应该是:
if(......)
{......}
std::string strRet;
......
return strRst;
我们也经常在循环中需要使用一些临时变量,该如何写呢:
//方法A
Widget w;
for(int i = 0;i < 10000;i++)
{
//对w进行操作
......
}
//方法B
for(int i = 0;i < 10000;i++)
{
Widget w;
//对w进行操作
......
}
对比方法A和方法B,不难看出,
方法A:1次构造 + 1次析构 + n次复制操作;
方法B:1000次构造 + 10000次析构;
我们需要对方法A和方法B的执行效率做客观的分析,如果Widget的构造和析构的成本大于复制操作的成本,则方法A更优,反之,则方法B更优。
类型转换也会影响程序执行效率,许多程序员相信,转型其实什么都没有做,只是告诉编译器把某种类型视作另一种类型。这种想法是错误的,任何类型转换都需要编译器编译出运行期间的执行代码。看看下面的代码:
//基类
class CBase
{
......
void func1();
};
//派生类1
class CSon1 : public CBase
{
......
void func1();
};
//其他的派生类
class CSon2 : public CBase{};
class CSon3 : public CBase{};
class CSon4 : public CBase{};
在这里我们写了一个基类CBase和派生至它4个类,每一个类中都含有func1()函数。现在,我们希望执行CSon1中的func1()函数,为此,我们声明了每一个类的指针,并将这些指针放入到一个容器中:
typedef std::vector<std::shared_ptr<CBase>> VPE;
VPE expPtrs;
... //将每个子类的指针放入容器中
for(VPE::iterator iter = expPtrs.begin();iter != expPtrs.end();++iter)
{
if(CSon1 *ptr = dynamic_cast<CSon1*>(iter->get()))
(*ptr)->func1();
}
尽管这种写法没有错,能够编译通过,但是,这样的写法是非常不提倡的,程序会遍历容器里的每一个元素,并对其做类型转换,会严重影响程序的执行效率。
有一种办法,我们可以将容器的类型写成CSon1,就可以避免类型转型:
typedef std::vector<std::shared_ptr<CSon1>> VPE;
... //将每个子类的指针放入容器中
for(......)
{
(*ptr)->func1();
}
但是这也会带来另一个弊端,如果我们要调用多个派生类的func1()函数,就需要声明多个容器,解决办法是,我们可以将func1()定义成virtual函数:
//基类
class CBase
{
......
virtual void func1();
};
//派生类1
class CSon1 : public CBase
{
......
virtual void func1();
};
typedef std::vector<std::shared_ptr<CBase>> VPE;
VPE expPtrs;
... //将每个子类的指针放入容器中
for(VPE::iterator iter = expPtrs.begin();iter != expPtrs.end();++iter)
{
(*ptr)->func1();
}
综上,转型会消耗程序的执行效率,程序中尽量避免强制转型,找到无需转型的替代方法。