天天速看:c++函数参数和返回值

2023-05-19 17:24:22 来源:博客园
c++函数参数和返回值函数存储位置函数参数入栈顺序初始化列表函数的返回值用参数引用来返回返回一个参数指针返回一个对象总结函数的几种变体inline 函数函数对象lambda 函数c++函数参数和返回值

c++一直以来是一个关注效率的代码,这样关于函数的参数传递和返回值的接收,是重中之重。下文提供了一些个人的见解。


(资料图片)

函数存储位置

函数参数在编译期展开,目前各平台的编译期均有不同。

名称存储位置
函数名称和逻辑代码段存储
函数参数和返回值栈中或者寄存器(64位会有6个寄存器使用)
new malloc 的变量
函数参数入栈顺序

微软有几种编译期属性,用来定义函数参数的顺序和堆栈。

关键字堆栈清理参数传递
__cdecl调用方在堆栈上按相反顺序推送参数(从右到左)
__clrcall不适用按顺序将参数加载到 CLR 表达式堆栈上(从左到右)。
__stdcall被调用方在堆栈上按相反顺序推送参数(从右到左)
__fastcall被调用方存储在寄存器中,然后在堆栈上推送
__thiscall被调用方在堆栈上推送;存储在 ECX 中的 this 指针
__vectorcall被调用方存储在寄存器中,然后按相反顺序在堆栈上推送(从右到左)

所以直接在函数参数上,调用表达式和函数来回去值的话,非常危险

初始化列表
class Init1{public:    void Print()    {        std::cout << a << std::endl;        std::cout << b << std::endl;        std::cout << c << std::endl;    }    int c, a, b;};

A这个类,可以通过 A a{1,2,3}; 来初始化对象。看着很美好,但是有几个问题需要注意。参数是的入栈顺序是跟着类的属性的顺序一致, 当前是 c, a, b;

int i = 0;Init1 a = {i++, i++, i++};a.Print();

当我如此调用的时候,得到的返回值是 1 2 0i++的执行顺序是从左到右,跟函数调用顺序无关。 另外不能有 构造函数

class Init1{public:Init1(int ia, int ib, int ic){std::cout << "construct" << std::endl;a = ia;b = ib;c = ic;}Init1(const Init1& other){std::cout << "copy " << std::endl;a = other.a;b = other.b;c = other.c;}void Print(){std::cout << a << std::endl;std::cout << b << std::endl;std::cout << c << std::endl;}int c, a, b;};

当我添加了构造函数的时候。 用下面代码测试。会得到两种结果

void Test_InitilizeList(){int i = 0;//Init1 a = { i++, i++, i++ }; // 0 1 2 Init1 a(i++, i++, i++); // 2 1 0 a.Print();}
函数的返回值

函数返回值的声明周期在函数体内。

用参数引用来返回
class Result{public:int result;};void GetResult(Result& result) ...

优点:

效率最高,因为返回值的对象在函数体外构造,可以一直套用, 可以一处构造,一直使用。安全,可以定义对象,并不用new或者malloc, 没有野指针困扰。缺点:代码可读性低,不够优美无法返回nullptr. 一般在 Result 中定义一个; 用来表示一个空对象。容易赋值到一个临时对象中,当调用GetResult({1})会赋值到一个 临时的 Result 对象中,拿不到返回值。正常来说也不会这样做。返回一个参数指针
class Result{public:int result;};Result* GetResult() ...

优点:

简洁明了参数传递快速缺点:指针如果在 函数内 static 需要考虑多线程。 如果是 new 出来的,多次调用效率不高指针无法重复使用,(可以用 std::share_ptr 增加对象池来解决问题。但会引入新的复杂度。)需要考虑释放的问题返回一个对象
class Result{public:int result;};Result GetResult() ...

优点:

没有内存泄露的风险简洁明了缺点:但有个别编译期优化选项问题,会导致一次构造两次拷贝, 第一次是函数体内对象向返回值拷贝,第二次是 返回值拷贝给外面接收参数的。开启编译期优化选项,并且是 在 return Result 的时候构造返回对象,才能优化。总结

一般如果是 简单结构体,用 返回一个临时对象的方式解决。如果使用 返回一个参数指针,一般改成返回一个id,用一个manager来管理内存机制。或者 共享内存,内存池来解决内存泄露后续的问题用 参数引用来返回的话,一般会这么定义 int GetResult(Result& result) 函数返回值,用来返回状态码,真正的数据,放到 result 中。

函数的几种变体inline 函数inline 函数是内联函数,是编译期优化的一种手段,一般是直接展开到调用者代码里,减少函数堆栈的开销。inline 标识只是建议,并不是一定开启内联。函数比较复杂或者递归有可能编译期不展开。dll 导出的时候,可以不用加导出标识,会直接导出到目标处。inline 在msvc的平台,只要实现头文件中,加不加内联是一样的. (警告顶级调到最高/Wall, 不加inline标识的函数会提示,未使用的内联函数将被删除。)inline 函数比全局函数更快,但是全局函数无法定义在头文件中(会报多重定义函数。)所以一般用class 包一层 static inline 函数,用来写工具类。函数对象
class A {public :    int value;      int operator() (int val) {        return value + val;    }}

上述代码是一个函数对象,重载operator()得到一个函数对象。int a = A{10}(1)会返回11, 显示构造了一个A{value=10}的对象,然后调用重载函数operator(), 返回 10 + 1 = 11上述代码因为是在头文件实现的,所以编译期会自动把operator()函数当成inline函数,执行效率很高。

lambda 函数

lambda 其实就是一个函数对象,会在编译期展开成一个函数对象体。

标签:

天天速看:c++函数参数和返回值

-[c++函数参数和返回值]( c函数参数和返回值)-[函数存储位置]( 函数存储位置)-[函数参数入栈顺序]( 函数参

2023-05-19 17:24:22

传艺科技(002866.SZ):公司钠离子电池可广泛应用在A00级车、储能等领域 视点

格隆汇5月19日丨有投资者在投资者互动平台向传艺科技002866002866SZ提问贵公司的钠电池客户主要有哪些随着

2023-05-19 17:19:04

意料之外、情理之中的曲线

5月16日,国家统计局公布了4月份经济数据。其中各分项数据整体维持在中性区间内,而且读数不错。但考虑到去

2023-05-19 16:23:18

世界焦点!态度测量技术

1、在现代市场营销观念下,营销人员必须设法了解消费者及有关人员对产品、品牌和企业的态度。前面介绍的一

2023-05-19 16:08:38

碧桂园摘得太原市3宗地块

5月18日,碧桂园微信公众号消息显示,5月17日碧桂园摘得太原市尖草坪区三给片区SWG-2310地块,次日(5月18

2023-05-19 15:32:28

中国旅游日,跟着外滩街道侨联 “环保游一江一河、低碳行一街一路”-焦点资讯

5月19日中午,由黄浦区外滩街道侨联主办,外滩街道山东北路居民区党总支、外滩街道城市建设管理事务中心共

2023-05-19 14:58:27

奥普光电董秘回复:公司子公司禹衡光学生产的光栅传感器可用于智能协作机器人、机械手、汽车智能激光雷达等领域_世界报资讯

奥普光电(002338)05月19日在投资者关系平台上答复了投资者关心的问题。

2023-05-19 14:18:37

当前快播:青岛:“十百千万”行动计划集聚“最强大脑”

科技日报记者宋迎迎“到2025年,全市成功对接博士后‘揭榜挂帅’项目10个;新增博士后站(基地)100个;培

2023-05-19 13:45:14

当前热讯:昂达官网_昂达VX9892GB

当前大家对于昂达VX9892GB都是颇为感兴趣的,大家都想要了解一下昂达VX9892GB,那么小美也是在网络上收集了一些

2023-05-19 13:03:34

唯品会怎么申请退款_唯品会怎么申请退款

唯品会回归的步骤:1 在手机上找到唯品会,点击进入,点击左下方一个人头形状的地方。2 点击待收货,进入页

2023-05-19 12:04:02
x 广告
x 广告

Copyright ©  2015-2022 南方经营网版权所有  备案号:粤ICP备18023326号-21   联系邮箱:855 729 8@qq.com