Effective C++ (E3 20、21)笔记之以传const引用代替传值、谨慎指定返回类型
2018-01-13 21:22
429 查看
传递函数参数时,使用传值方式会对传入对象进行复制。如以下代码:
然后有一个以类AA的参数的函数:
使用按值传递试验:
结果:
![](http://img.blog.csdn.net/20180113211950019)
可见按值传递时,派生类及其基类都被copy了一次,退出函数时派生类及其基类都被析构了一次。
如果按const引用传递,可回避所有的构造析构动作:
结果:
![](http://img.blog.csdn.net/20180113212636720?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYnJhaG1zamlhbmc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
按值传递除了拷贝析构临时对象以外,还会造成对象切割问题:
如果有一个以类A(基类)为参数的函数:
以AA对象传递:
结果:
![](http://img.blog.csdn.net/20180113213707255?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYnJhaG1zamlhbmc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
由结果可知,当以一个继承类对象按值传递给基类形参时,其会被视为一个基类对象,表现出的行为(调用的函数)是基类的,继承类的特质被切割掉了。因为正是基类的构造函数建立了它。
按const引用传递后,表现出的行为和传入的对象一致了:
结果:
![](http://img.blog.csdn.net/20180113215112318?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYnJhaG1zamlhbmc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
因为传递引用意味着真正传递的是指针,多态的实现依靠的是指针和引用。
另外,对于内置类型、STL迭代器和函数对象,按值传递的效率反而比传递const引用高些。对这几种小型对象按值传递往往比较恰当。
虽然传递引用能提升效率,在需要返回一个对象时,也一刀切地指定返回类型为引用却会带来问题。
1. 如果在函数内定义栈对象,函数结束时该栈对象销毁,却返回一个指向该已销毁的对象的引用。其结果无疑是灾难性的:
2. 如果在函数内分配堆对象,函数结束时其析构是个问题。在某些场景下,即便调用者小心翼翼还是可能无法获得这个引用背后的指针来delete,导致内存泄漏。
3. 如果在函数内指定static对象,第一就有线程安全性的疑虑。此外,由于local static对象在多个函数调用内只维持一份拷贝,是不是应该用static首先就是个疑问。纯粹为了返回引用而千方百计实现返回引用实在是本末倒置的行为。
因此,必须返回一个新对象的写法是:就让那个函数返回一个新对象。
AA retAA(){
AA aa0;
return aa0;
}
相比上述糟糕的、想方设法返回引用的而带来额外的危险与开销,返回一个新对象带来的构造、析构成本反而不算什么了。
#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;
}
相比上述糟糕的、想方设法返回引用的而带来额外的危险与开销,返回一个新对象带来的构造、析构成本反而不算什么了。
相关文章推荐
- effective c++ 条款20(用const引用代替值传递)
- C++ 传值,传引用和传指针-参考Effective C++ 第三版Item20~21
- Item 21:需要返回对象时,不要返回引用 Effective C++笔记
- Effective c++学习笔记——条款10:令operator=返回一个*this的引用
- Effective c++学习笔记——条款10:令operator=返回一个*this的引用
- 必须返回对象时,别妄想返回引用(Effective C++_21)
- const 类型的函数不能返回非const类型的引用
- 十二章 类————返回自身类型的引用 const与非const的重载,和mutable(好的风格)
- effective C++笔记之条款20、21:避免public接口出现数据成员、尽可能使用const
- Effective C++ 第二版 20)避免接口数据 21)使用const
- 访问器中谨慎返回引用类型对象
- 宁以const引用传递代替按值传递(内置类型除外)
- 访问器中谨慎返回引用类型对象
- 宁以const引用传递代替按值传递(内置类型除外)
- Effective C++ 学习笔记:让operator=返回*this的引用
- Effective C++之Item 20: 用 pass-by-reference-to-const(传引用给 const)取代 pass-by-value(传值)
- 读书笔记 effective c++ Item 21 当你必须返回一个对象的时候,不要尝试返回引用
- Effective C++--条款20:适当地用pass-by-reference-to-const代替pass-by-value
- Effective C++ (E3 37)笔记之不重新指定继承而来的默认参数值
- 函数返回的临时对象为const类型,const引用