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

Effective C++ (E3 20、21)笔记之以传const引用代替传值、谨慎指定返回类型

2018-01-13 21:22 429 查看
传递函数参数时,使用传值方式会对传入对象进行复制。如以下代码:

#include <iostream>
using namespace std;

class A
{
public:
A(){
cout<<"A::A()"<<endl;
}
virtual ~A(){
cout<<"A::~A()"<<endl;
}
A(const A&){
cout<<"A::A(const A&)"<<endl;
}
virtual void print(){
cout<<"A::print"<<endl;
}
};

class AA:public A
{
public:
AA():A(){
cout<<"AA::AA()"<<endl;
}
~AA(){
cout<<"AA:~AA()"<<endl;
}
AA(const AA& aa):A(aa){	//no12, baseclass copycons should be called when define derived class copycons
cout<<"AA::AA(const AA&)"<<endl;
}
virtual void print(){
cout<<"AA::print"<<endl;
}
};

然后有一个以类AA的参数的函数:

void callAA(AA a)
{
cout<<"at callAA=========="<<endl;
}

使用按值传递试验:

int main()
{
AA aa;
cout<<"before callAA=========="<<endl;
callAA(aa);
cout<<"before return=========="<<endl;
return 0;
}


结果:



可见按值传递时,派生类及其基类都被copy了一次,退出函数时派生类及其基类都被析构了一次。

如果按const引用传递,可回避所有的构造析构动作

void callAA(const AA& a)
{
cout<<"at callAA=========="<<endl;
}

结果:



按值传递除了拷贝析构临时对象以外,还会造成对象切割问题:

如果有一个以类A(基类)为参数的函数:

void callA(A a)
{
cout<<"at callA=========="<<endl;
a.print();
}

以AA对象传递:

int main()
{
AA aa;
cout<<"before callA=========="<<endl;
//callA(aa);
cout<<"before return=========="<<endl;
return 0;
}

结果:



由结果可知,当以一个继承类对象按值传递给基类形参时,其会被视为一个基类对象,表现出的行为(调用的函数)是基类的,继承类的特质被切割掉了。因为正是基类的构造函数建立了它。

按const引用传递后,表现出的行为和传入的对象一致了:

void callA(const A& a)
{
cout<<"at callA=========="<<endl;
a.print();
}

结果:



因为传递引用意味着真正传递的是指针,多态的实现依靠的是指针和引用

另外,对于内置类型、STL迭代器和函数对象,按值传递的效率反而比传递const引用高些。对这几种小型对象按值传递往往比较恰当。

虽然传递引用能提升效率,在需要返回一个对象时,也一刀切地指定返回类型为引用却会带来问题。

1. 如果在函数内定义栈对象,函数结束时该栈对象销毁,却返回一个指向该已销毁的对象的引用。其结果无疑是灾难性的:

AA& retAA(){
AA aa0;
return aa0;
}

retAA().print();

2. 如果在函数内分配堆对象,函数结束时其析构是个问题。在某些场景下,即便调用者小心翼翼还是可能无法获得这个引用背后的指针来delete,导致内存泄漏。
3. 如果在函数内指定static对象,第一就有线程安全性的疑虑。此外,由于local static对象在多个函数调用内只维持一份拷贝,是不是应该用static首先就是个疑问。纯粹为了返回引用而千方百计实现返回引用实在是本末倒置的行为。

因此,必须返回一个新对象的写法是:就让那个函数返回一个新对象

AA retAA(){
AA aa0;
return aa0;
}
相比上述糟糕的、想方设法返回引用的而带来额外的危险与开销,返回一个新对象带来的构造、析构成本反而不算什么了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: