缺省状况下c++以by value的方式传递对象至函数,函数参数都是以实参的副本为初值,当传递参数时,pass-by-value的操作会导致昂贵的时间开销。
例如一个student类继承自person类:
class Person
{
public:
Person();
virtual ~Person();
//...
private:
std::string name;
std::string address;
};
class Student: public Person
{
public:
Student();
~Student();
//...
private:
std::string schoolName;
std::string schoolAddress;
};
如果以pass-by-value的方式传递对象:
bool validateStudeng(Student s); //函数以by value方式接受学生
Student plato;
bool platoIsOk = validateStudeng(plato);
当上述函数被调用时,首先调用一次Student的copy构造函数,以plato为蓝本将s初始化。当validateStudent返回时,s会被销毁。因此,对此函数而言,参数的传递成本是:一次Student的copy构造函数调用,一次Student析构函数被调用。但是这只是一部分开销。
此外:在构造Student对象时,必须先构造Person对象,在一个Person对象中,又有两个string对象。所以在以by-value方式传递Student对象时,会导致1次Student构造函数调用,1次Person构造函数调用,4次string构造函数调用,共6次构造函数调用,6次析构函数调用。共12次构造、析构函数调用。
按pass-by-refference-to-const的方法传递效率会提高很多。
bool validateStudent(const Studeng& s);//没有任何构造和析构函数被调用,因为没有任何新对象创建
这个const是重要的,因为pass-by-value时候不会修改传进去的参数原来的值(修改的是副本的值)。
pass-by-value传递派生类的时候有可能造成参数被切割
class Windows
{
public:
//...
std::string name() const;//返回窗口名称
virtual void display() const;//显示窗口及其内容
};
class WindoesWithScrollBars: public Windows
{
public:
//...
virtual void display() const;
};
//...
void printNameAndDisplay(Windows w) //对象会被切割 显示Windows类的名字
{
std::cout << w.name;
w.display;
}
void printNameAndDisplay(cosnt Windows& w) //对象不会被切割 显示WindowsWithScrollBars的名字
{
std::cout << w.name;
w.display;
}
WindoesWithScrollBars wwsb;
printNameAndDisplay(wwsb);
pass-by-reference-to-const时,传递进去什么参数就是什么参数,不会发生类型转换(参数切割)。
在c++编译器的底层,reference往往以指针实现出来。
当传递的是内置类型或者STL的迭代器或函数对象(仿函数)时,pass-by-value效率优于pass-by-reference-to-const。
总结:
1. 尽量以pass-by-reference-to-const替换pass-by-value。前者通常比较高效,并可避免切割问题。
2. 以上规则不适用于内置类型,STL的迭代器和函数对象(仿函数),对他们而言,pass-by-value更适合。