c++函数参数和返回值
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 0
i++的执行顺序是从左到右,跟函数调用顺序无关。 另外不能有 构造函数
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++函数参数和返回值的更多相关文章
- python函数进阶(函数参数、返回值、递归函数)
函数进阶 目标 函数参数和返回值的作用 函数的返回值 进阶 函数的参数 进阶 递归函数 01. 函数参数和返回值的作用 函数根据 有没有参数 以及 有没有返回值,可以 相互组合,一共有 4 种 组合形 ...
- javascript函数参数、返回值类型检查
实现带参数.返回值类型声明的js函数: 类型定义:window.Str = Type.Str = Type.define('STRING', Type.isStr);var Per = Type.de ...
- Python基础之函数参数与返回值进阶
参数作用:如果外界希望在函数内部处理数据,就可以将数据作为参数传入函数内部: 返回值作用:如果希望一个函数函数执行完成后,向外界报告函数的执行结果,就可以使用函数的返回值. 函数的返回值 进阶 利用元 ...
- 04 python学习笔记-函数、函数参数和返回值(四)
函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段.函数能提高应用的模块性,和代码的重复利用率.Python提供了许多内建函数,比如print(),我们也可以自己创建函数,这叫做用户自定 ...
- JS基础语法---函数---介绍、定义、函数参数、返回值
函数: 把一坨重复的代码封装,在需要的时候直接调用即可 函数的作用: 代码的重用 函数需要先定义,然后才能使用 函数名字:要遵循驼峰命名法 函数一旦重名,后面的会把前面的函数覆盖 Ctrl +鼠标左键 ...
- Java中能否利用函数参数来返回值
转自https://blog.csdn.net/da_da_xiong/article/details/70039532 我们在写代码时通常会遇到一种情况,就是我们可能希望在一个函数操作完成后返回两个 ...
- c++函数参数或返回值为函数指针
C++中函数指针的形式为:返回值类型 + 参数类型,函数没有值类型,但是却可以声明函数的指针,因为函数是可寻址的,存放在内存中的代码段,可以从指针访问. 函数指针可以声明为: void (*pF)(v ...
- ajax中error函数参数与返回值详解 200 300 400 500
201-206:都表示服务器成功处理了请求的状态代码,说明网页可以正常访问. 200:(成功) 服务器已成功处理了请求.通常,这表示服务器提供了请求的网页. 201:(已创建) 请求成功且服务器已创建 ...
- python中函数的参数和返回值
目录 函数 目标 01. 函数参数和返回值的作用 1.1 无参数,无返回值 1.2 无参数,有返回值 1.3 有参数,无返回值 1.4 有参数,有返回值 02. 函数的返回值 进阶 示例 -- 温度和 ...
- c&c++函数的参数和返回值的传递终结版
c++函数的参数和返回值的传递方式有三种:值传递.指针传递和引用传递. 在这之前先看几个例子: 一, int a=10; int b=a; b+=10; 此时b是a的一个拷贝,改变b的值,a并不会受到 ...
随机推荐
- 手把手教你基于luatos的4G(LTE Cat.1)模组接入华为云物联网平台
摘要:本期文章采用了4G LTE Cat.1模块,编程语言用的是lua,实现对华为云物联网平台的设备通信与控制 本文分享自华为云社区<基于luatos的4G(LTE Cat.1)模组接入华为云物 ...
- linux中查看用户和组信息小结
查看当前登录用户的组内成员groups 查看当前登录用户名whoami 查看tom用户所在的组,以及组内成员groups tom 查看所有的用户信息cat /etc/passwd 用户名.密码.用户i ...
- 续集来了!我让 GPT-4 用 Laf 三分钟写了个完整的待办事项 App
书接前文,上篇文章我们教大家如何三分钟时间用 Laf 实现一个自己的 ChatGPT. 一觉醒来,GPT-4 已经发布了! GPT-4 实现了真正的多模态,可以把纸笔画的原型直接写出网页代码.读论文时 ...
- Kafka 物理存储机制
一个商业化消息队列的性能好坏,其文件存储机制设计是衡量一个消息队列服务技术水平和最关键指标之一.下面将从 Kafka文件存储机制和物理结构角度,分析 Kafka是如何实现高效文件存储,及实际应用效果. ...
- 全网最详细中英文ChatGPT-GPT-4示例文档-从0到1快速入门python代码解释应用——官网推荐的48种最佳应用场景(附python/node.js/curl命令源代码,小白也能学)
目录 Introduce 简介 setting 设置 Prompt 提示 Sample response 回复样本 API request 接口请求 python接口请求示例 node.js接口请求示 ...
- Windows下解决python pip命令下载慢的方法(超简单)
首先,常用的国内镜像: 1 https://pypi.tuna.tsinghua.edu.cn/simple/ 清华大学(推荐) 2 http://pypi.douban.com/simple/ 豆瓣 ...
- CentOS7-自动化部署web集群
一.项目要求 1.创建role,通过role完成项目(可能需要多个role) 2.部署nginx调度器(node2主机) 3.部署2台lnmp服务器(node3,node4主机) 4.部署mariad ...
- 计网学习笔记七 IP protocol basic
在这一节讲了IP协议的基本内容:包括IPv4提供的操作.数据报在IPv4下是怎么样的结构.数据报是怎样切片发送的.IPv4的编址方式有什么--IPv6在下一节讲网络层协议簇时细讲. IPv4协议的具体 ...
- 如何在Solidity中建立DAO(去中心化自治组织)?
本文将帮助您理解 DAO 的概念,并帮助您构建一个基本的 DAO. 什么是 DAO? 您可以将 DAO 视为基于互联网的实体(比如企业),由其股东(拥有代币和比例投票权的成员)共同拥有和管理.在 DA ...
- Python中,类的特殊方法与内置函数的关联
目录 Python类 Python类的设计原则 特殊方法[Special methods] Duck typing 内置函数 English Version The key design princi ...