您的位置:首页 > 编程语言 > C语言/C++

Effective C++ rule 20.传参与传引用

2017-09-05 09:18 127 查看

前言

Rule 20 阐述了我们在设置函数的形参时,尽量以pass by reference const 的形式,少用pass by value.主要基于效率和行为考虑的。

代码讲解

#include <stdio.h>
#include <iostream>
#include <string>
using namespace std;
class Person
{
public:
string name;
public:
Person()
{

}
virtual ~Person()
{

}
public:
virtual void say() const
{
cout << "Person:I am " << name;
}
};
class Student :public Person
{
public:
Student() :Person()
{

}
~Student()
{

}
public:
virtual void say() const
{
cout << "Student: I am " << name;
}
};
void Sayv(Person p)
{
p.say();
}
void Sayr(const Person& p)
{
p.say();
}
int main()
{
Student stu;
Sayv(stu);
Sayr(stu);
return 0;
}


1.我们来看调用Sayv与Sayr的开销: Sayv(Person p) 传入的时候需要调用Person的复制构造函数,在Sayv()结束的时候,需要调用Person的析构函数。Sayr(Person &p)没上面的步骤。

2.再看两个函数输出什么:

Sayv()调用的是Person的say()函数。而Sayr()调用的Student类的say()函数。Sayr(Person &p)其实就是使用了多态性来调用say()函数。

Sayv()因为是pass by value.导致stu被切割成只剩下基类Person的东西了。

为什么内置类型一般使用pass by value会更高效安全

文中还提到


我们编程验证一下:

int fv(int i)
{
return i*i;
}
int fr(const int &i)
{
return i*i;
}
int main()
{
int x = 5;
int y = fv(x);
int z = fr(x);
return 0;
}


汇编代码:

60:     int x = 5;
010364FF  mov         dword ptr [x],5   把5存入x对应的内存中
61:     int y = fv(x);
01036506  mov         eax,dword ptr [x]  取x内存中存储的值到eax
01036509  push        eax               传入eax
0103650A  call        fv (010312B2h)
0103650F  add         esp,4
01036512  mov         dword ptr [y],eax
62:     int z = fr(x);
01036515  lea         eax,[x]          取x变量的有效地址到eax,就是传入x的地址进去。
01036518  push        eax               传入eax.
01036519  call        fr (010314BFh)
0103651E  add         esp,4
01036521  mov         dword ptr [z],eax


其实对于内置类型(包括指针),传参数还是传引用效率上是差不多的,因为两个都要访问内存若干次。但是传参数的版本可以在不加const的情况下保证函数内部的操作不会影响到原来的变量X。

另外!

严格来说,传参效率还要低一些,因为它需要先取x的地址,然后将x的地址传到MAR寄存器,再从地址总线定位到内存单位,通过数据总线拿回X的值;而传引用的话只需要取x的地址,没有接下来访存的操作。

总结:

一般情况下,pass by reference const会比pass by value 少了很多复制构造函数和析构函数的调用,从这个角度来看pass by reference const 是很受推崇的

pass by reference const利用多态性,可以避免pass by value对子类进行切割的问题。我们一般不想看到子类被切割了,但是也不排除某些场合下 我们就需要这个效果。

pass by reference const的函数其实还有一个不太好的问题就是:因为传入的是一个常引用,导致在函数内部只能调用对象的const方法!比如上面的例子中 say()就需要是const函数。当然这或许也不是什么问题,在这个规定下,开发人员开发出来的类将更加规范,严格遵循const 对象只能调用const方法来保证对象的一致性。不过,个人还是更喜欢没有带const的pass by reference ,哈哈哈
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: