参考:https://blog.csdn.net/sfh366958228/article/details/38701767
条款20:尽量使用 const引用传递 代替 值传递
默认情况下C++是以值传递的形式传递对象到函数的。除非特别指定,否则函数参数都是以实际实参的副本为初值。调用端所获的也是函数返回值的一个副本。这些副本是由对象的拷贝构造函数产生,这会使值传递非常费时。
特别是在一个结构复杂的类中,例如:
class Student : public Person {
public:
student();
~student();
private:
std::string name;
}
当有以下函数:
bool validateStudent(Student s);
Student plato;
bool platoIsok=validateStudent(plato);
即以置传递方式传递一个Student对象时,会导致调用一次person拷贝构造函数,一次student拷贝构造函数,string类拷贝构造函数,当函数内的student副本被销毁时,每一个构造函数地调用都需要一个对应的析构函数调用动作。
所以可以将值传递方式的函数进行优化,如下
bool validateStudent(Student s);// 优化前
bool validateStudent(const Student &s);// 优化后
这样的话效率将大大提高。
不仅如此,通过引用传递可以避免派生类被视作一个基类的情况(因为派生类通过基类的拷贝构造函数创建了一个只有基类属性的副本)。
但是并不是任何时候使用引用传递都会比使用值传递效率高,因为引用传递往往意味着传递指针,所以如果参数是内置类型的话,通过值传递会比引用传递效率高。
在STL的迭代器与函数对象中,使用值传递效率也会比引用传递高,因为习惯上他们都被设计为值传递。
总结:
1)尽量以引用传递代替值传递,前者往往效率更高,并可以避免切割问题。
2)这个规则并不适用于内置类型、以及STL的迭代器和函数对象。对他们而言,值传递效率更高。
条款21 必须返回对象时,不要返回其引用
函数创建对象的方法有两个:在stack空间或在heap空间创建。如果定义一个局部变量,就是在stack空间创建对象
const Rational& operator*(const Rational& lhs,const Rational& rhs)
{
Rational result(lhs.n*rhs.n,lhs.d*rhs.d);
return result;
}
这个函数返回一个指向result的引用,但result是一个局部对象,而局部对象在函数退出之前就被销毁了。
如果在堆内构造一个对象,并返回引用指向它,堆对象由new创建
const Rational& operator* (const Rational& lhs,const Rational&rhs)
{
Rational* result=new Rational(lhs.n*rhs.n,lhs.d*rhs.d);
return *result;
}
因为函数中使用了new,也就需要delete,但是其中并没有实施delete的操作,会导致资源泄露
上面的操作都是因为对返回的结果调用了构造函数而受到惩罚,如果不调用构造函数呢?
如果让返回的引用指向一个被定义于函数内部的static Rational 对象(不会调用构造函数了)
const Raional& operator*(const Rational& lhs,const Rational&rhs)
{
static Rational result;
result=lhs*rhs;
return result;
}
bool operator==(const Rational&lhs,const Rational&rhs);
Rational a,b,c,d;
....
if((a*b)==(c*d))
{
当乘积相等时,做适当的相应动作;
}
else
{
当乘积不等时,做适当的相应动作;
}
结果就是,表达式((a*b)==(c*d))总是被核算为true,不论a,b,c,d,的值是什么。
将代码重写拆开迷雾:if(operator==(operator*(a,b) operator*(c,d)))
因为在operator==调用之前已经有l两个operator*起作用,每一个都返回引用指向operator*内部定义的static Rational 对象。
虽然两次operator*调用的确各自改变了static Rational 对象值,但由于他们返回的都是引用,因此调用端看到的永远都是static Rational 的现值。
总结:
绝不要返回一个指向局部对象的指针或者引用,或一个指向堆对象的引用,或返回指向一个有可能同时需要多个这样对象的局部静态对象的指针或引用。