Effective C++条款20:宁以pass-by-reference-to-const替换pass-by-value

默认情况下C++以值方式传递对象至函数
除非你另外指定,否则函数参数都是以实际参数的复件位初始值。而调用端所获得也是函数返回值的一个复件。这些复件由对象的复制构造函数产出。
这可能使得pass-by-value成为昂贵的操作。
比如:

class Person 
{
private:
	string lname;
	string fname;
public:
	Person();
	virtual ~Person();
	virtual void show()const;
};
class Student : public Person
{
public:
	Student();
	~Student();
	...
private:
	string schoolName;
	string schoolAddress;
	virtual void show()const;
};

考虑以下代码:

bool validateStudent(Student s);
Student p;
bool pisOK =validateStudent(s);

当上面的函数被调用会发生什么事情?
首先Student的复制构造函数会被调用,以p为蓝本将s初始化。
其次validateStudent返回s会被销毁。
因此,对这个函数而言。参数传递的成本是:一次Student 复制构造函数调用,一次Student析构函数调用.

Student对象内有两个string对象,每次构造一个Student对象也就构造了两个string对象。
此外Student对象继承自Person对象,一个Person对象又有两个string对象.
最终结果是以值方式传递一个Student对象会导致调用一次Student复制构造函数、一次Person 复制构造函数、四次复制构造函数。
Student复件被销毁,还要调用析构函数,总体成本是:六次构造函数和六次析构函数

如果我们以pass by reference to-const来传递,效率就高很多了:

bool validateStudent(const Student& s);

上面这种方式,没有任何构造函数或析构函数被调用

此外以by reference方式传递参数也可以避免对象切割问题.
当一个派生类对象以by value方式传递并被视为一个基类对象,基类的构造函数会被调用,而派生的特化性质全被切掉了,仅仅留下一个基类对象.
假如有这样一个函数,用来打印上面的类的信息:

void ShowInformation(Person P)
{
	p.show();
}

当你以以下形式调用这个函数,会发生什么情况?

Student s;
ShowInformation(s);

s会被构造成为一个Person对象,它是按值传递,派生的所有特化信息都会被切除,在这个函数内调用的总是Person::show而不是Student::Show.
解决切割问题的办法,就是by reference-to-const的方式传递:

void ShowInformation(const Person& P)
{
	p.show();
}

现在,传进来的是什么类型,p就表现出什么类型。

在C++中,references往往以指针实现出来,因此pass by reference通常意味真正传递是指针。如果是内置类型的话(比如int),pass by value往往效率更高。这个也适用于STL的迭代器和函数对象,因为习惯上它们都被设计为passed by value.

注意:
不要认为小型类型都是适用于pass-by-value, 甚至它们是用户自定义的类也可以,对象小并不意味着复制构造函数不昂贵,某些编译器对待内置类型和用户自定义类型的态度截然不同,比如某些编译器拒绝把只有一个double组成的对象放进缓存中,却乐意对一个double这样做, 两个拥有相同的底层表述,当这种事情发生时,你应该以by reference方式传递此对象,因为编译器会将指针放进缓存内.

此外,另一个理由是,用户自定义类型,其大小很容易变化,一个类可能现在很小,将来有可能变得很大。

总结:

1.按引用传递通常比较高效,此外还可以避免切割问题.
2.以上规则不适用于内置类型,STL迭代器和函数对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值