函数的传参和传返回值,分为两种模式:传值和传引用。
传值就是传整个对象,传引用就是传对象的引用(地址)。当对象本身比较小时,可以直接传值,但当对象比较大时我们一般会传引用以节省内存和减少拷贝。这是C++的机制,在java中都是传引用,所以不用像C++一样区分值语义和引用语义。
对于传参一般建议都使用传引用,但对于返回值而言,我们不能直接返回对象引用,因为,函数调用完后会清栈,引用指飞。但传值我们又担心临时变量的拷贝降低性能,所以我们可能写出如下代码,返回值用指针包裹。
shared_ptr<A> fun()
make_shared<A> ptr;
return ptr;
这当然万无一失,但明显变麻烦了。实际上我们可以放心大胆地返回对象。下面进行论述:
C/C++函数返回对象的原理:
A fun2()
A a1();
return a1;
void fun1()
A a2=fun2();
a1是在函数fun2中堆栈中的对象,在return时,会将其拷贝构造到外层函数fun1的堆栈中(这个对象是一个匿名对象,是一个右值,马上会被析构),之后将其拷贝构造产生对象a2。这是没有任何编译器优化的情况。
一般情况下,编译器会采用RVO(return value optimization)优化,参看《深度探索C++对象模型》。下面是一个例子
//原函数
Point3d factory()
Point3d po(1,2,3)
return po;
int main()
Point3d p = factory();
return 1;
编译器优化后的示例代码
factory(const Point3d &_result)
Point3d po;
po.Point3d::Point3d(1,2,3);
_result.Point3d::Point3d(po); //用po拷贝构造_result;
po.Point3d::~Point3d(); //po对象析构
return;
int main()
Point3d _result;
factory(_result);
Point3d p=result;
return 1;
大体意思是说,会在值传递返回值的函数中,将返回值改写成传引用参数。这样可以少一次临时变量的构造。这是编译器优化时帮我们做的。
总结起来就是放心大胆地返回一个对象实体,这并不会有多余的开销,编译器会帮我们优化。
C++中有这样一种对象:它在代码中看不到,但是确实存在。它是临时对象—由编译器定义的一个没有命名的非堆对象(non-heap object)。为什么研究临时对象?主要是为了提高程序的性能以及效率,因为临时对象的构造与析构对系统性能而言绝不是微小的影响,所以我们应该去了解它们,知道它们如何造成,从而尽可能去避免它们。
临时对象通常产生于以下4种情况:
· 类型装换
· 按值传递
· 按值返回
· 对象定义
下面我们逐一看看:
1、类型转换:它通常是为了让函数调用成功而产生临时对象。发生于 “传递某对象给一个函数,而其类型与它即将绑定上去的参数类型不同”
④ c++14中增加广义捕获(Generalized capture):即在捕获子句中增加并初始化新的变量,该变量不需要在lambda表达式所处的闭包域中存在;捕获的外部变量列表,通过逗号分隔,可进行传值捕获或者引用捕获,lambda表达式与这些捕获的外部变量会构成一个闭包(Closure),外部变量为闭包的成员变量。lambda表达式的闭包含有局部变量的引用(悬挂引用 Dangling references),在超出创建它的作用域之外的地方被使用的话,将引发内存越界访问。如有疑问,敬请留言。
返回对象,无非两种方式,返回栈对象和堆对象指针,栈对象指针不能返回,因为可能使用不该使用的内存,堆对象也不能直接返回,因为会产生内存泄漏。下面,我们分析两种返回方式的优缺点,及针对缺点的解决方案。
返回栈对象:
优点:不用手动释放内存,避免了内存泄漏;
缺点:会产生对象拷贝,如果对象比较大,比如,对象里面有大数组,会产生性能开销。
返回堆对象指针:
优点:不会产生对象拷贝,对性能友好;
缺点:函数调用之后手动释放对象,代码管理难度和内存泄漏风险提高。
那有没有办...
当成员函数或独立的函数返回对象时,有几种返回方式可供选择。可以返回指向对象的引用、指向对象的 const 引用、const 对象。
返回指向 const 对象的引用
使用 const 引用的常见原因是旨在提高效率,但对于何时采用这种方法存在一些限制。如果函数返回传递给它的对象,可以通过返回引用来提高效率。例如,编写函数 Max(),它返回两个 Object 对象中较大的一个(假设 Object 类重载了比较运算符)。
// Version 1
Object Max(const Object & ob
本来还以为这一篇就能搞定基础,结果想不到的是,最后几节的知识点这么多,比较还没接触过,所以还是分为两篇,这一篇只要说map容器和函数对象,特别是对象适配器讲的比较多,对象适配器是新知识点,所以讲的细了一点。
C++学习 十四、类的进阶(6)返回对象前言类与动态内存小结函数返回对象返回非const对象返回const对象返回非const引用对象返回const引用对象示例后记
本篇首先小结类中动态内存的使用,然后记录返回对象。
类与动态内存小结
构造函数中使用new分配动态内存,则析构函数中必须使用delete释放动态内存。
析构函数只有一个。因此有多个构造函数时,要考虑new与new []的兼容性。
构造函数如果分配动态内存,则需要定义一个深拷贝复制构造函数,重载一个深拷贝赋值运算符。
函数返回对象
原文链接:https://www.cnblogs.com/yanhai307/p/10935665.html
参考链接:
https://www.cnblogs.com/mini-coconut/p/8542560.html
https://www.cnblogs.com/ysherlock/p/7822287.html
在C++程序中,一个函数返回值是一个对象时,返回的是函...
这一章主要讲的是返回值优化,这个优化通常会交给编译器实现,用于加快源代码执行,通过对源代码进行转化并消除对象实现的。
按返回值构造
以下的例子主要是complex实现复数的类:
这个类的操作符函数,比如加法的函数如下:
以上可以看出,加法的结果是返回值返回的。实际上编译器内部会进行操作a=b+c这样的结果,a会被编译器临时构造出来,b和c都是引用传递,因此两个参数的函数会被临时创建为三个参数。同样的调用的时候也会发生变化,需要传递三个参数,这个就是返回值优化的步骤之一。